2010-06-04 15 views
10

Probabilmente una risposta estremamente semplice a questa domanda estremamente semplice:Utilizzando scanf in un ciclo while

Sto leggendo "C Primer Plus" di Pratta e lui continua utilizzando l'esempio

while (scanf("%d", &num) == 1)... 

È il == 1 davvero necessario? Sembra che si possa solo scrivere:

while (scanf("%d", &num)) 

Sembra che il test di uguaglianza è inutile dal momento che scanf restituisce il numero di oggetti letti e 1 renderebbe il ciclo while vero. È la ragione per assicurarsi che il numero di elementi letti sia esattamente 1 o è assolutamente superfluo?

+0

Sì, sembra piuttosto ridondante per me ... – tzaman

risposta

22

In C, 0 viene valutato su falso e tutto il resto su true. Quindi, se scanf ha restituito EOF, che è un valore negativo, il ciclo verrebbe valutato su true, che non è quello che si vorrebbe.

+0

EOF era l'elemento chiave qui, bella cattura. –

3

Hai capito correttamente il codice C.

A volte il motivo per testare il numero di elementi letti è che qualcuno vuole assicurarsi che tutti gli elementi siano stati letti invece che scanf si sia ritirato presto quando l'input non corrispondeva al tipo previsto. In questo caso particolare non aveva importanza.

Di solito scanf è una scelta scadente di funzioni perché non soddisfa le esigenze di input interattivo da un utente umano. Di solito una combinazione di fgets e sscanf produce risultati migliori. In questo caso particolare non aveva importanza.

Se in seguito i capitoli spiegano perché alcuni tipi di pratiche di codifica sono migliori di questo semplice esempio, bene. Ma se no, dovresti scaricare il libro che stai leggendo.

D'altra parte, il tuo codice sostitutivo non è esattamente un sostituto. Se scanf restituisce -1, verrà eseguito il ciclo while.

+0

Sbagliato, guarda le altre risposte. Restituisce -1 quando viene rilevato EOF o si verifica un errore di lettura. –

+2

"Sbagliato, guarda le altre risposte." - Intendi dire sbagliato, vedi la mia risposta, perché è per questo che ho scritto "Se scanf restituisce -1, il tuo ciclo while verrà eseguito". –

8

Poiché scanf restituisce il valore EOF (che è -1) alla fine del file, il ciclo come scritto è corretto. Viene eseguito finché l'input contiene un testo corrispondente a %d e si arresta al primo non corrispondente o alla fine del file.

Sarebbe stato più chiaro a colpo d'occhio se scanf si aspettavano più di un ingresso ....

while (scanf("%d %d", &x, &y)==2) { ... } 

uscirebbe dal ciclo quando la prima volta è stato in grado di abbinare due valori, sia a causa di fine del file di immagine (scanf restituisce EOF (che è -1)) o errore di ingresso corrispondenti (ad esempio l'ingresso xyzzy 42 non corrisponde %d %d così scanf fermate primo guasto e restituisce 0 senza scrivere a uno o xy) quando restituisce un valore inferiore a 2.

Ovviamente, scanf è non il tuo amico quando analizza l'input reale da umani normali. Ci sono molte insidie ​​nella gestione dei casi di errore.

Edit: Corretto un errore: scanf rendimenti EOF sulla fine del file, o un intero non negativo contando il numero di variabili è impostata correttamente.

Il punto chiave è che poiché qualsiasi valore diverso da zero è TRUE in C, non riuscire a testare correttamente il valore restituito in un ciclo come questo può facilmente portare a comportamenti imprevisti.In particolare, while(scanf(...)) è un ciclo infinito a meno che non incontri il testo di input che non può essere convertito in base al suo formato.

E non posso sottolineare abbastanza fortemente che scanf è non tuo amico. Una combinazione di fgets e sscanf potrebbe essere sufficiente per alcuni semplici parsing, ma anche in questo caso è facilmente sopraffatta da casi limite ed errori.

1

Mentre sei corretto non è strettamente necessario, alcune persone lo preferiscono per diversi motivi.

Innanzitutto, confrontandolo con 1 diventa un valore booleano esplicito (vero o falso). Senza il confronto, stai testando un numero intero, che è valido in C, ma non in lingue successive (come C#).

In secondo luogo, alcune persone leggono la seconda versione in termini di while ([function]), anziché while ([return value]), e vengono momentaneamente confuse testando una funzione, quando ciò che è chiaramente inteso è testare il valore di ritorno.

Questo può essere completamente una questione di preferenze personali, e per quanto mi riguarda, entrambi sono validi.

1

Uno probabilmente potrebbe scriverlo senza un confronto esplicito (vedere la risposta del JRL), ma perché si dovrebbe? Direi che le condizioni di confronto-less dovrebbero essere usate solo con valori che hanno una semantica esplicitamente booleana (come una chiamata isdigit(), per esempio). Tutto il resto dovrebbe usare un confronto esplicito. In questo caso (il risultato di scanf) la semantica è marcatamente non-booleana, quindi il confronto esplicito è in ordine.

Inoltre, il confronto che di solito si può omettere è normalmente un confronto con zero. Quando senti il ​​bisogno di omettere il confronto con qualcos'altro (come 1 in questo caso) è meglio pensarci due volte e assicurati di sapere cosa stai facendo (vedi di nuovo la risposta del JRL).

In ogni caso, quando il confronto può essere omesso in modo sicuro e in realtà lo si omette, il reale significato semantico della condizione rimane lo stesso. Non ha assolutamente alcun impatto sull'efficienza del codice risultante, se è qualcosa di cui ti stai preoccupando.