Discussione:
scanf domanda
(troppo vecchio per rispondere)
mirko ballarini
2023-11-13 21:14:54 UTC
Permalink
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
enoquick
2023-11-14 03:09:31 UTC
Permalink
Post by mirko ballarini
Ciao,
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
[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



|___|
jak
2023-11-14 12:50:30 UTC
Permalink
Post by mirko ballarini
Ciao,
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
Ballarini 1234 30
Creolo 4354 12
Ficarra 6544 23
Picone 7756 15
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
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.
mirko ballarini
2023-11-14 21:05:52 UTC
Permalink
Post by jak
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.
Grazie a tutti, stasera ho imparato cose nuove e ve ne sono grato
Giovanni
2023-11-15 16:45:52 UTC
Permalink
Post by jak
In ogni caso penso che non ti capiterà mai di vedere del codice
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/ >
jak
2023-11-16 13:19:43 UTC
Permalink
Post by Giovanni
Post by jak
In ogni caso penso che non ti capiterà mai di vedere del codice
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.
Anche perché se uno non riesce a leggere ciò che scrive, mi vien da
dire: chi ha colpa del suo mal pianga se stesso.
Post by Giovanni
In questi casi se viene controllato che tutti
gli argomenti sian stati riconosciuti si ha una discreta affidabilità
nel loro uso.
Ma devono essere proprio dati creati da un programma fatto apposta
complementarmente, perché già solo leggere un .csv prodotto da terzi
diventa un rischio. Basterebbe che chi lo produce, in un impeto di
bizzarrìa o perché sta catalogando poesie, decidesse di sostituire il
separatore standard ',' (utile nelle poesie) con un trattino '-' ed ecco
che, d'un tratto, alcune cifre facenti parte del record di ventano
negative :^D

Una "discreta affidabilità" è decisamente poco dal punto di vista
professionale. In effetti, più che un'opiniione, stavo esprimendo una
statistica: in olre 3 decaadi di codifica in C mi sarà capitato 2 o 3
volte di trovare funzioni del gruppo scanf in codice professionale. Ne
ho notato un largo uso, invece, nei programmini che io definisco 'di
servizio' che sempre più spesso, però, sono sostituiti da script shell,
perl, awk o python coi quali diventa semplice approfittare delle regex
con le quali il controllo può avvenire in modo più 'robusto'.
Post by Giovanni
Ciao
Giovanni
Ciao.

Continua a leggere su narkive:
Loading...