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.