Jak wyczyścić bufor wejściowy w C?
Mam następujący program:
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;
}
Jak wyjaśnił autor powyższego kodu:
Program nie będzie działał poprawnie, ponieważ w linii 1, gdy użytkownik naciśnie Enter, zostanie pozostawiony w buforze wejściowym znak 2: Enter key (ASCII code 13)
i \n (ASCII code 10)
. Dlatego w linii 2 odczyta \n
i nie będzie czekać, aż użytkownik wprowadzi znak.
getchar()
(ch2 = getchar();
) nie czyta Enter key (13)
, zamiast \n
charakter?
Następnie autor zaproponował 2 sposoby rozwiązania takich probremów:
Użycie
fflush()
-
Napisz taką funkcję:
void clear (void) { while ( getchar() != '\n' ); }
Ten kod zadziałał. Ale nie mogę się wytłumaczyć, jak to działa? Ponieważ w instrukcji while używamy getchar() != '\n'
, czyli odczytujemy dowolny pojedynczy znak oprócz '\n'
? jeśli tak, to w buforze wejściowym nadal pozostaje znak '\n'
?
11 answers
Program nie będzie działał poprawnie, ponieważ w linii 1, gdy użytkownik naciśnie Enter, zostanie pozostawiony w buforze wejściowym znak 2: klawisz Enter (kod ASCII 13) i \n (kod ASCII 10). Dlatego w linii 2 odczyta \n i nie będzie czekać, aż użytkownik wprowadzi znak.
Zachowanie, które widzisz na linii 2 jest poprawne, ale to nie jest do końca poprawne Wyjaśnienie. W przypadku strumieni w trybie tekstowym nie ma znaczenia, jakich linii używa twoja platforma (czy powrót karetki (0x0D) + linefeed (0x0A), bare CR lub bare LF). Biblioteka uruchomieniowa C zajmie się tym za ciebie: twój program zobaczy tylko '\n'
dla nowych linii.
Jeśli wpiszesz znak i wciśniesz enter, to ten znak wejściowy zostanie odczytany w linii 1, a następnie '\n'
zostanie odczytany w linii 2. Zobacz używam scanf %c
, aby odczytać odpowiedź Y/ N, ale później Dane wejściowe są pomijane. z komp.lang.c FAQ.
Jeśli chodzi o proponowane rozwiązania, zobacz (ponownie z komp.lang.c FAQ):
- Jak spłukać oczekujące dane wejściowe, aby głowica typowa użytkownika nie była odczytywana przy następnym monicie? Czy
fflush(stdin)
zadziała? - Jeśli
fflush
nie działa, czego mogę użyć do spłukania danych wejściowych?
Które zasadniczo stwierdzają, że jedynym przenośnym podejściem jest zrobić:
while ((c = getchar()) != '\n' && c != EOF) { }
Twoja pętla getchar() != '\n'
działa, ponieważ po wywołaniu getchar()
, zwrócony znak został już usunięty ze strumienia wejściowego.
Również, czuję się zobowiązany do zniechęcić cię do używania scanf
całkowicie: dlaczego wszyscy mówią, aby nie używać scanf
? Czego powinienem użyć zamiast tego?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-18 00:52:04
Możesz to zrobić (również) w ten sposób:
fseek(stdin,0,SEEK_END);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-17 13:36:48
Linie:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
;
Nie odczytuje tylko znaków przed linią ('\n'
). Odczytuje wszystkie znaki w strumieniu (i odrzuca je) aż do następnego wiersza włącznie (lub napotkany jest EOF). Aby test był prawdziwy, musi najpierw odczytać strumień liniowy; więc kiedy pętla się zatrzyma, strumień liniowy był ostatnim odczytanym znakiem, ale został odczytany.
A co do tego, dlaczego czyta linefeed zamiast return carriage, to dlatego, że system przetłumaczył powrót do liniowca. Po naciśnięciu enter sygnalizuje koniec linii... ale strumień zawiera kanał liniowy, ponieważ jest to normalny znacznik końca linii dla systemu. To może być zależne od platformy.
Również użycie fflush()
na strumieniu wejściowym nie działa na wszystkich platformach; na przykład ogólnie nie działa na Linuksie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-15 05:10:37
Przenośnym sposobem na wyczyszczenie końca wiersza, który już próbowałeś przeczytać częściowo jest:
int c;
while ( (c = getchar()) != '\n' && c != EOF ) { }
To odczytuje i odrzuca znaki, dopóki nie otrzyma \n
, Co zasygnalizuje koniec pliku. Sprawdza również przed EOF
w przypadku, gdy strumień wejściowy zostanie zamknięty przed końcem linii. Typ c
musi być int
(lub większy), aby móc utrzymać wartość EOF
.
Nie ma przenośnego sposobu, aby dowiedzieć się, czy jest więcej linii po bieżącej linii (jeśli nie ma, wtedy getchar
zablokuje wejście).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-28 02:47:18
Ale nie potrafię wyjaśnić, jak to działa? Ponieważ w instrukcji while używamygetchar() != '\n'
, co oznacza odczyt dowolnego pojedynczego znaku poza'\n'
?? jeśli tak, to w buforze wejściowym nadal pozostaje znak'\n'
??? Czy coś źle zrozumiałam??
Rzecz może nie zdawać sobie sprawy, że porównanie dzieje się po getchar()
usuwa znak z bufora wejściowego. Więc kiedy osiągniesz '\n'
, jest zużyty i wtedy wyłamujesz się z pętla.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-26 03:12:43
Możesz spróbować
scanf("%c%*c", &ch1);
Gdzie % * c akceptuje i ignoruje nową linię
Jeszcze jedna metoda zamiast fflush (stdin) wywołującego nieokreślone zachowanie można napisać
while((getchar())!='\n');
Nie zapomnij średnika po pętli while
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-10 15:04:30
unsigned char a=0;
if(kbhit()){
a=getch();
while(kbhit())
getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;
-lub -
Użyj może użyj _getch_nolock()
..???
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-21 03:17:55
Napotkałem problem próbując zaimplementować rozwiązanie
while ((c = getchar()) != '\n' && c != EOF) { }
Zamieszczam mały 'kod B' dla każdego, kto może mieć ten sam problem.
Problem polegał na tym, że program pozwalał mi łapać znak '\n', niezależnie od znaku enter, oto kod, który dał mi problem.
Kod A
int y;
printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
continue;
}
printf("\n%c\n", toupper(y));
I korekta polegała na "złapaniu" znaku (n-1) tuż przed obliczeniem warunkowego w pętli while, oto kod:
Kod 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));
Możliwe wyjaśnienie jest takie, że dla przerwania pętli while, musi ona przypisać wartość' \n ' do zmiennej y, więc będzie to ostatnia przypisana wartość.
Jeśli coś przeoczyłem z wyjaśnieniem, kodem a lub kodem B, proszę mi powiedzieć, Jestem ledwo nowy w c.
Hope it helps someone
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-20 15:26:04
Krótki, przenośny i zadeklarowany w stdio.h
stdin = freopen(NULL,"r",stdin);
Nie jest zawieszony w nieskończonej pętli, gdy na stdin nie ma nic do spłukania, jak następująca dobrze znana linia:
while ((c = getchar()) != '\n' && c != EOF) { }
Trochę drogi, więc nie używaj go w programie, który musi wielokrotnie czyścić bufor.
Ukradł współpracownikowi:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-22 21:28:24
char choice;
do{
printf("\n *");
printf("\n Do you want to continue? (y/n) ");
choice = getchar();
if(getchar() != '\n'){
fflush(stdin);
}
}while( choice != 'n' );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 17:56:16
Innym nie wspomnianym jeszcze rozwiązaniem jest użycie: rewind (stdin);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-26 02:40:41