Newsgroup: it.comp.lang.c
Titolo: scanf domanda

Ciao,
per errore ho scritto una scanf come sotto, ottenendo risultati bizzarri:
 
while(fscanf(Fin, "%s, %d, %d", stringa, &matricola, &voto)!= EOF) {
        printf("Nome = %s\nMatricola = %d\nVoto = %d\n", stringa, matricola, voto);
    }
 
Si notino le "," fra i %s e %d, che ovviamente non ci vanno.
Volevo chiedere, che effetto ha l'inserimento delle virgole nello scanf?
Sembrano ritornare degli indirizzi di memoria.
Senza le virgole il programma funziona come dovrebbe.
 
grazie
 
 
 
file da cui legge:
Ballarini 1234 30
Creolo 4354 12
Ficarra 6544 23
Picone 7756 15
 
Output con le virgole:
Nome = Ballarini
Matricola = 1
Voto = 1058674984
Nome = 1234
Matricola = 1
Voto = 1058674984
Nome = 30
Matricola = 1
Voto = 1058674984
Nome = Creolo
Matricola = 1
Voto = 1058674984
Nome = 4354
Matricola = 1
Voto = 1058674984
Nome = 12
Matricola = 1
Voto = 1058674984
Nome = Ficarra
Matricola = 1
Voto = 1058674984
Nome = 6544
Matricola = 1
Voto = 1058674984
Nome = 23
Matricola = 1
Voto = 1058674984
Nome = Picone
Matricola = 1
Voto = 1058674984
Nome = 7756
Matricola = 1
Voto = 1058674984
Nome = 15
Matricola = 1
Voto = 1058674984
 
Process finished with exit code 0
 

 
[CUT]
 
Semplice, non essendo un % o spazio  viene letto il carattere 
specificato e scartato
Se il carattere letto non coincide lo scan termina
 
 
#include <stdio.h>
 
int main() {
 
	const char p[]="56 678";
	int x=99,y=98;
	if (sscanf(p,"%d 6 %d",&x,&y) == EOF) {
		printf("scanf error\n");
	}
	printf("%d %d\n",x,y);
	return 0;
}
 
output:
56 78
 
 
 
	if (sscanf(p,"%d 7 %d",&x,&y) == EOF) {
 
	output: 56 98
 
	come si puo vedere dall'output y non e' cambiato
 
 
 
|___|
 

mirko ballarini ha scritto:

Ciao,
la risposta alla tua domanda sarebbe: se metti una virgola nella stringa
di parsificazione, la fscanf si aspetta di trovarla durante lo scan e se
fossi stato meno 'lasco' col test di fine loop te ne saresti accorto da
te.
La fscanf ritorna EOF per fine file ma anche se non riesce a trovare dei
dati che soddisfino almeno la prima delle formattazioni. Nel tuo caso
legge il primo nome, non trova la virgola, fallisce il resto della
parsificazione ed, essendo in un loop, ricomincia a leggere dal punto in
cui era arrivata con la preceente chiamata, trova '1234' lo acquisisce
come primo parametro (Nome), poi si aspetta una virgola che non trova e
tutto si ripete acquisendo '30' come primo parametro e così via. Ciò che
stampi per 'Matricola' e 'Voto' non è significativo perché la fscanf,
fallendo per l'assenza della virgola, non vi ha scritto nulla.
Sarebbe, quindi, buona norma verificare che la fscanf abbia
effettivamente letto tutti i campi che ci si aspetta:
 
while((ret = fscanf(fp, "...", nome, &matr, &voto)) == 3)
 
Verrebbe da dire: beh, allora aggiungo le virgole nei file di dati e
tutto dovrebbe funzionare. Purtroppo non basta perché con la stringa di
parse che hai usato:
 
"%s, %d, %d"
 
la virgola verrebbe a far parte del Nome, quindi con:
 
Ballarini, 1234, 30
 
in Nome verrebbe caricato "Ballarini," (nota la virgola in fondo),
quindi la fscanf cercherebbe una virgola che ormai è stata letta, non la
trova più e fallisce. Per ovviare a questo problema si può sostituire %s
con qualcosa di meno generico che escluda la virgola:
 
"%[a-zA-Z], %d, %d"
 
in questo modo però bisogna tener conto del fatto che la virgola deve 
seguire la parola ecquisita con  %[a-zA-Z], cioè, ad esempio, 
funzionerebbe con:
 
Ballarini, 1234, 30
 
ma non con:
 
Ballarini , 1234 , 30
 
siccome lo spazio in una riga di parse significa "0 o piò separatori
(spazi/tab), aggiungendo uno spazio prima della virgola il parse
funzionerebbe con la virgola in qualsiasi sistemazione:
 
Ballarini, 1234, 30
Ballarini , 1234 , 30
Ballarini,1234,30
 
a questo punto mettendo al posto della virgola qualcosa che ignori ciò
che non è un numero, come ad esempio:
 
"%[a-zA-Z]%*[^0-9]%d%*[^0-9]%d"
 
rende possibile separare i campi anche con altri separatori:
 
Ballarini, 1234;:30
Ballarini - 1234 / 30
Ballarini:1234;30
 
a questo punto perché non mettere la cigliegina sulla torta e fare in
modo che la fscanf non vada a prendere dati dalle linee successive? Ci
appendiamo anche il riconoscimento di fine linea e lo skip di quel che è
di troppo dopo i 3 valori che interessano:
 
  " %[A-Za-z]%*[^0-9\n]%d%*[^0-9\n]%d%*[^\n] "
 
così dovrebbe funzionare correttamente anche con un file dati tipo:
 
Ballarini,1234:30
Creolo/4354/12
Ficarra-6544 23  tanto va la gatta...
Picone 7756 15
 
In ogni caso penso che non ti capiterà mai di vedere del codice
professionale dove venga usata una delle funzioni del gruppo fscanf.
 

 professionale dove venga usata una delle funzioni del gruppo fscanf.
 
 
Grazie a tutti, stasera ho imparato cose nuove e ve ne sono grato
 
 

 professionale dove venga usata una delle funzioni del gruppo fscanf.
 
Le funzioni della famiglia scanf() sono sicure solo se usate con 
stringhe e/o file generati da programma che hanno un formato ben 
definito ed immutabile. In questi casi se viene controllato che tutti 
gli argomenti sian stati riconosciuti si ha una discreta affidabilità 
nel loro uso.
 
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   < 
https://giovanni.homelinux.net/
 >

 Giovanni
 
Ciao.