Come cancellare il buffer di input in C?

Ho il seguente programma:

int main(int argc, char *argv[]) { char ch1, ch2; printf("Input the first character:"); // Line 1 scanf("%c", &ch1); printf("Input the second character:"); // Line 2 ch2 = getchar(); printf("ch1=%c, ASCII code = %d\n", ch1, ch1); printf("ch2=%c, ASCII code = %d\n", ch2, ch2); system("PAUSE"); return 0; } 

Come l’autore del codice di cui sopra ha spiegato: Il programma non funzionerà correttamente perché alla Linea 1, quando l’utente preme Invio, lascerà nel carattere del buffer di input 2: Enter key (ASCII code 13) e \n (ASCII code 10) . Pertanto, alla riga 2, leggerà \n e non aspetterà che l’utente inserisca un carattere.

OK, ho capito. Ma la mia prima domanda è: perché il secondo getchar() ( ch2 = getchar(); ) non legge il Enter key (13) , piuttosto che il carattere \n ?

Successivamente, l’autore ha proposto 2 modi per risolvere tali problemi:

  1. usa fflush()

  2. scrivere una funzione come questa:

     void clear (void) { while ( getchar() != '\n' ); } 

Questo codice ha funzionato in realtà. Ma non posso spiegarmi come funziona? Perché getchar() != '\n' while, usiamo getchar() != '\n' , che significa leggere qualsiasi singolo carattere tranne '\n' ? se è così, nel buffer di input rimane ancora il carattere '\n' ?

Il programma non funzionerà correttamente perché alla Linea 1, quando l’utente preme Invio, lascerà nel carattere del buffer di input 2: tasto Invio (codice ASCII 13) e \ n (codice ASCII 10). Pertanto, alla riga 2, leggerà \ n e non aspetterà che l’utente inserisca un carattere.

Il comportamento che vedi alla riga 2 è corretto, ma non è la spiegazione corretta. Con i flussi in modalità testo, non importa quali terminazioni di linea vengono utilizzate dalla piattaforma (sia carriage return (0x0D) + linefeed (0x0A), bare CR o LF nuda). La libreria di runtime C si prenderà cura di te per te: il tuo programma vedrà solo '\n' per i newline.

Se hai digitato un carattere e premuto enter, allora quel carattere di input verrebbe letto dalla riga 1, e quindi '\n' sarebbe letto dalla riga 2. Vedi Sto usando scanf %c per leggere una risposta Y / N, ma l’input successivo viene saltato. dalle FAQ di comp.lang.c.

Per quanto riguarda le soluzioni proposte, vedere (di nuovo dalle FAQ di comp.lang.c):

  • Come posso svuotare l’input in sospeso in modo che il typeahead di un utente non venga letto al prompt successivo? fflush(stdin) funzionerà?
  • Se fflush non funziona, cosa posso usare per scaricare l’input?

che in sostanza afferma che l’unico approccio portatile è quello di fare:

 while ((c = getchar()) != '\n' && c != EOF) { } 

Il tuo getchar() != '\n' funziona perché una volta chiamato getchar() , il carattere restituito è già stato rimosso dal stream di input.

Inoltre, mi sento obbligato a scoraggiarvi dall’utilizzare scanf interamente: perché tutti dicono di non usare scanf ? Cosa dovrei usare invece?

Puoi farlo (anche) in questo modo:

 fseek(stdin,0,SEEK_END); 

Le linee:

 int ch; while ((ch = getchar()) != '\n' && ch != EOF) ; 

non legge solo i caratteri prima del linefeed ( '\n' ). Legge tutti i caratteri nello stream (e li elimina) fino a includere il linefeed successivo (o EOF viene rilevato). Perché il test sia vero, deve prima leggere il linefeed; così, quando il ciclo si interrompe, il carattere è stato letto l’ultimo carattere, ma è stato letto.

Per quanto riguarda il motivo per cui legge un avanzamento riga anziché un ritorno a capo, è perché il sistema ha tradotto il ritorno a un avanzamento riga. Quando viene premuto enter, ciò indica la fine della linea … ma il stream contiene invece un avanzamento di riga poiché questo è il normale indicatore di fine riga per il sistema. Potrebbe dipendere dalla piattaforma.

Inoltre, l’uso di fflush() su un stream di input non funziona su tutte le piattaforms; ad esempio, in genere non funziona su Linux.

Un modo portatile per cancellare fino alla fine di una linea che hai già provato a leggere parzialmente è:

 int c; while ( (c = getchar()) != '\n' && c != EOF ) { } 

Questo legge e scarta i caratteri finché non ottiene \n che segnala la fine del file. Controlla anche EOF nel caso in cui il stream di input si chiuda prima della fine della linea. Il tipo di c deve essere int (o più grande) per poter contenere il valore EOF .

Non c’è un modo portatile per scoprire se ci sono altre linee dopo la linea corrente (se non ci sono, allora getchar bloccherà per l’input).

Ma non posso spiegarmi come funziona? Perché getchar() != '\n' while, usiamo getchar() != '\n' , che significa leggere qualsiasi singolo carattere tranne '\n' ?? se è così, nel buffer di input rimane ancora il carattere '\n' ??? Sto fraintendendo qualcosa ??

La cosa che potresti non getchar() è che il confronto avviene dopo che getchar() rimuove il carattere dal buffer di input. Quindi quando raggiungi il '\n' , viene consumato e quindi si esce dal ciclo.

Puoi provare

 scanf("%c%*c", &ch1); 

dove% * c accetta e ignora la nuova riga

un altro metodo invece di fflush (stdin) che richiama il comportamento non definito che puoi scrivere

 while((getchar())!='\n'); 

non dimenticare il punto e virgola dopo il ciclo

 unsigned char a=0; if(kbhit()){ a=getch(); while(kbhit()) getch(); } cout<(a) & 0xFF)< 

-o-

usare magari usare _getch_nolock() .. ???

Incontro un problema nel tentativo di implementare la soluzione

 while ((c = getchar()) != '\n' && c != EOF) { } 

Inserisco un piccolo aggiustamento ‘Codice B’ per chiunque abbia lo stesso problema.

Il problema era che il programma mi impediva di catturare il carattere ‘\ n’, indipendentemente dal carattere di invio, ecco il codice che mi ha dato il problema.

Codice A

 int y; printf("\nGive any alphabetic character in lowercase: "); while( (y = getchar()) != '\n' && y != EOF){ continue; } printf("\n%c\n", toupper(y)); 

e la regolazione consisteva nel “catturare” il carattere (n-1) appena prima che il condizionale nel ciclo while venisse valutato, ecco il codice:

Codice B

 int y, x; printf("\nGive any alphabetic character in lowercase: "); while( (y = getchar()) != '\n' && y != EOF){ x = y; } printf("\n%c\n", toupper(x)); 

La ansible spiegazione è che per il ciclo while da interrompere, deve assegnare il valore ‘\ n’ alla variabile y, quindi sarà l’ultimo valore assegnato.

Se ho perso qualcosa con la spiegazione, codice A o codice B per favore dimmi, sono appena nuovo in c.

spero che aiuti qualcuno

Breve, portatile e dichiarato in stdio.h

 stdin = freopen(NULL,"r",stdin); 

Non si blocca in un ciclo infinito quando non c’è nulla su stdin da svuotare come la seguente linea ben nota:

 while ((c = getchar()) != '\n' && c != EOF) { } 

Un po ‘caro quindi non usarlo in un programma che ha bisogno di cancellare ripetutamente il buffer.

Rubato da un collega 🙂

 char choice; do{ printf("\n *"); printf("\n Do you want to continue? (y/n) "); choice = getchar(); if(getchar() != '\n'){ fflush(stdin); } }while( choice != 'n' ); 

Un’altra soluzione non menzionata ancora è da usare: rewind (stdin);