scanf () lascia la nuova riga char nel buffer


93

Ho il seguente programma:

Come ho letto nel libro C, l'autore dice che ha scanf()lasciato un nuovo carattere di riga nel buffer, quindi, il programma non si ferma alla riga 4 per consentire all'utente di inserire i dati, piuttosto memorizza il nuovo carattere di riga in c2 e si sposta su linea 5.

È giusto?

Tuttavia, questo accade solo con chari tipi di dati? Perché non ho riscontrato questo problema con inti tipi di dati come nella riga 1, 2, 3. È corretto?


A volte viene suggerito che fflush(stdin)può essere utilizzato prima della chiamata a scanf()per un singolo carattere. Si prega di leggere Utilizzofflush(stdin) per una discussione dei pro e dei contro e delle alternative a quel metodo (che funziona, più o meno, su Windows e non funziona nella maggior parte degli altri posti).
Jonathan Leffler

Potresti per favore farci sapere a quale libro ti riferisci?
surya kiran

Risposte:


82

La scanf()funzione salta automaticamente gli spazi iniziali prima di provare ad analizzare conversioni diverse dai caratteri. I formati dei caratteri (principalmente %c; anche i set di scansione %[…]- e %n) sono l'eccezione; non saltano gli spazi bianchi.

Utilizzare " %c"con uno spazio vuoto iniziale per saltare lo spazio bianco facoltativo. Non utilizzare uno spazio finale in una scanf()stringa di formato.

Nota che questo ancora non consuma alcuno spazio vuoto finale lasciato nel flusso di input, nemmeno alla fine di una riga, quindi fai attenzione se usi anche getchar()ofgets() sullo stesso flusso di input. Stiamo solo facendo in modo che scanf salti gli spazi bianchi prima delle conversioni, come fa per %de altre conversioni non di caratteri.


Notare che le "direttive" diverse dagli spazi (da usare terminologia POSIX scanf ) diverse dalle conversioni, come il testo letterale in scanf("order = %d", &order);, non salta neanche gli spazi. Il letterale orderdeve corrispondere al carattere successivo da leggere.

Quindi probabilmente lo vuoi " order = %d"se vuoi saltare una nuova riga dalla riga precedente ma richiedi comunque una corrispondenza letterale su una stringa fissa, come questa domanda .


9
%c, %n, %[]Sono i 3 aspettative specificati che non consumano spazio presente in testa.
chux - Ripristina Monica

@chux Così fa in altri casi, Scanf cancella tutti gli spazi bianchi prima nel buffer o li ignora perché immessi ma sono ancora lì?
Suraj Jain

@SurajJain Sì,
chux - Ripristina Monica il

3
Vedere Trailing blank in scanf()format string e scanf()chiedere due volte l'input mentre mi aspetto che chieda solo una volta per una discussione sugli spazi finali nelle stringhe di formato. Sono una cattiva idea - sorprendentemente cattiva se ti aspetti l'interazione umana e cattiva per l'interazione del programma.
Jonathan Leffler

32

Usa scanf(" %c", &c2);. Questo risolverà il tuo problema.


8

Un'altra opzione (che ho ottenuto da qui ) è leggere e scartare la nuova riga utilizzando l' opzione di soppressione dell'assegnazione . Per farlo, mettiamo semplicemente un formato per leggere un carattere con un asterisco in mezzo% e c:

scanf leggerà quindi il carattere successivo (cioè il ritorno a capo) ma non lo assegnerà a nessun puntatore.

Alla fine, tuttavia, sarei secondo l'ultima opzione delle FAQ :

Oppure, a seconda delle tue esigenze, potresti anche dimenticarti di scanf () / getchar (), usare fgets () per ottenere una riga di testo dall'utente e analizzarla tu stesso.


3
Il problema con questa tecnica è che se l'utente digita aquindi spazio e poi nuova riga, la conversione del carattere soppressa legge lo spazio e lascia ancora la nuova riga. Se l'utente digita supercalifragilisticexpialidociousquando ti aspetti a, hai molti caratteri extra con cui occuparti. Non puoi mai dire se una conversione soppressa finale ha successo, non vengono conteggiati nel ritorno da scanf().
Jonathan Leffler

4

Utilizzare getchar()prima di chiamare il secondo scanf().


1
Funziona a condizione che l'utente non abbia digitato nient'altro, ad esempio spazi vuoti finali. Ma non è buono come un ciclo che esegue la scansione alla nuova riga successiva: int c; while ((c = getchar()) != EOF && c != '\n') ;(scritto su tre righe quando non è in un commento). Spesso è sufficiente; non è infallibile (e devi ricordare che gli sciocchi sono molto abili nel far crollare le cose).
Jonathan Leffler
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.