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 klawisz Enter, pozostawi w buforze wejściowym 2 znaki: 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.
OK, rozumiem. Ale moje pierwsze pytanie brzmi: dlaczego druga getchar()
( ch2 = getchar();
) nie czyta Enter key (13)
, a nie \n
znaku?
Następnie autor zaproponował 2 sposoby rozwiązania takich problemów:
posługiwać się
fflush()
napisz funkcję taką jak ta:
void clear (void) { while ( getchar() != '\n' ); }
Ten kod faktycznie działał. Ale nie potrafię sobie wytłumaczyć, jak to działa? Ponieważ w instrukcji while używamy getchar() != '\n'
, oznacza to przeczytanie dowolnego pojedynczego znaku z wyjątkiem '\n'
? jeśli tak, to w buforze wejściowym nadal pozostaje '\n'
znak?
getchar()
odczyta i zwróci te znaki; użytkownik nie będzie musiał ponownie naciskać klawisza Enter. Ponadto podczas termios może być wspólne w systemie Linux , nie jest częścią biblioteki standardowej C .scanf(" %c", &char_var)
pracy i ignorowania znaku nowej linii przez dodanie spacji przed specyfikatorem% c?Możesz to (również) zrobić w ten sposób:
fseek(stdin,0,SEEK_END);
źródło
fseek
jest dostępnystdin
?Przenośny sposób na wyczyszczenie do końca wiersza, który już próbowałeś częściowo przeczytać, to:
int c; while ( (c = getchar()) != '\n' && c != EOF ) { }
To czyta i odrzuca znaki, dopóki nie otrzyma,
\n
co oznacza koniec pliku. Sprawdza równieżEOF
w przypadku, gdy strumień wejściowy zostanie zamknięty przed końcem linii. Typc
musi byćint
(lub większy), aby móc utrzymać wartośćEOF
.Nie ma przenośnego sposobu sprawdzenia, czy po bieżącej linii jest więcej wierszy (jeśli ich nie ma,
getchar
blokuje wejście).źródło
Linie:
int ch; while ((ch = getchar()) != '\n' && ch != EOF) ;
nie czyta tylko znaków przed wysuwem wiersza (
'\n'
). Odczytuje wszystkie znaki w strumieniu (i odrzuca je), aż do następnego nowego wiersza (lub napotkanego EOF) włącznie . Aby test był prawdziwy, musi najpierw odczytać nowy wiersz; więc kiedy pętla się zatrzymuje, wysuw wiersza był ostatnim odczytanym znakiem, ale został odczytany.Jeśli chodzi o to, dlaczego czyta znak nowego wiersza zamiast powrotu karetki, to dlatego, że system przetłumaczył powrót na nowy wiersz. Po naciśnięciu klawisza Enter sygnalizuje koniec linii ... ale zamiast tego strumień zawiera wysunięcie wiersza, ponieważ jest to normalny znacznik końca linii dla systemu. Może to zależeć od platformy.
Ponadto używanie
fflush()
na strumieniu wejściowym nie działa na wszystkich platformach; na przykład generalnie nie działa w systemie Linux.źródło
while ( getchar() != '\n' );
to nieskończona pętla powinnagetchar()
powrócić zEOF
powodu końca pliku.int ch; while ((ch = getchar()) != '\n' && ch != EOF);
można użyćMożesz nie zdawać sobie sprawy z tego, że porównanie ma miejsce po
getchar()
usunięciu znaku z bufora wejściowego. Więc kiedy osiągniesz'\n'
, jest zużyty, a następnie wyrwiesz się z pętli.źródło
możesz spróbować
scanf("%c%*c", &ch1);
gdzie% * c akceptuje i ignoruje znak nowej linii
jeszcze jedna metoda zamiast fflush (stdin), która wywołuje niezdefiniowane zachowanie, które możesz napisać
while((getchar())!='\n');
nie zapomnij o średniku po pętli while
źródło
"%*c"
skanuje dowolny znak (i nie zapisuje go), czy to nowy wiersz, czy coś innego. Kod opiera się na tym, że drugi znak to nowa linia. 2)while((getchar())!='\n');
to nieskończona pętla, która powinnagetchar()
powrócić zEOF
powodu końca pliku.Napotykam problem podczas próby wdrożenia rozwiązania
while ((c = getchar()) != '\n' && c != EOF) { }
Publikuję małe dostosowanie „Kod B” dla każdego, kto może mieć ten sam problem.
Problem polegał na tym, że program wychwycił znak „\ n”, niezależnie od znaku enter, oto kod, który spowodował 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));
a korekta polegała na `` złapaniu '' znaku (n-1) tuż przed oceną warunku 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żliwym wyjaśnieniem jest to, że aby pętla while została przerwana, musi przypisać wartość „\ n” zmiennej y, więc będzie to ostatnia przypisana wartość.
Jeśli przegapiłem coś z wyjaśnieniem, kodem A lub kodem B, powiedz mi, jestem ledwo nowy w c.
mam nadzieję, że to komuś pomoże
źródło
while
pętli. Po pętli możesz uznać,stdin
że jest czysty / wyraźny iy
będzie trzymać albo '\n
', alboEOF
.EOF
jest zwracany, gdy nie ma nowej linii i bufor jest wyczerpany (jeśli wejście przepełniłoby bufor przed[ENTER]
naciśnięciem). - Skutecznie używaszwhile((ch=getchar())!='\n'&&ch!=EOF);
do przeżuwania każdego znaku wstdin
buforze wejściowym.unsigned char a=0; if(kbhit()){ a=getch(); while(kbhit()) getch(); } cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;
-lub-
użyć może użyć
_getch_nolock()
.. ???źródło
kbhit()
igetch()
są funkcjami zadeklarowanymi<conio.h>
i dostępnymi standardowo tylko w systemie Windows. Mogą być emulowane na maszynach typu Unix, ale wymaga to pewnej ostrożności.Innym rozwiązaniem, o którym jeszcze nie wspomniano, jest użycie: rewind (stdin);
źródło
Dziwię się, że nikt o tym nie wspomniał:
scanf("%*[^\n]");
źródło
Krótki, przenośny i zadeklarowany w stdio.h
stdin = freopen(NULL,"r",stdin);
Nie zawiesza się w nieskończonej pętli, gdy na stdin nie ma nic do spłukiwania, jak następująca dobrze znana linia:
while ((c = getchar()) != '\n' && c != EOF) { }
Trochę drogie, więc nie używaj go w programie, który musi wielokrotnie czyścić bufor.
Ukradł od współpracownika :)
źródło
freopen
jest taki, że nie można go przenosićstdin
. To jest makro.Spróbuj tego:
stdin->_IO_read_ptr = stdin->_IO_read_end;
źródło