Как очистить входной буфер в C?
У меня есть следующая программа:
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;
}
Как пояснил автор вышеприведенного кода:
Программа не будет работать должным образом, потому что в строке 1, когда пользователь нажимает Enter, он оставит в буфере входного буфера 2 символ: Enter key (ASCII code 13)
и \n (ASCII code 10)
. Поэтому в строке 2 он будет читать \n
и не будет ждать ввода пользователем символа.
Хорошо, я понял. Но мой первый вопрос: почему второй getchar()
(ch2 = getchar();
) не читает символ Enter key (13)
, а не \n
?
Далее автор предложил два способа решения таких проблем:
Этот код действительно работал. Но я не могу объяснить, как это работает? Потому что в выражении while мы используем getchar() != '\n'
, то есть читаем любой отдельный символ, кроме '\n'
? если да, то во входном буфере остается символ '\n'
?
Ответы
Ответ 1
Программа не будет работать должным образом, потому что в строке 1, когда пользователь нажимает Enter, он оставит в буфере входного сигнала 2 символ: введите ключ (код ASCII 13) и \n (код ASCII 10). Поэтому в строке 2 он будет читать \n и не будет ждать ввода пользователем символа.
Поведение, которое вы видите в строке 2, является правильным, но это не совсем правильное объяснение. В потоках текстового режима не имеет значения, какие линии вы используете для своей платформы (возврат каретки (0x0D) + linefeed (0x0A), голый CR или голый LF). Библиотека времени выполнения C позаботится об этом для вас: ваша программа увидит только '\n'
для новых строк.
Если вы набрали символ и нажали enter, тогда этот входной символ будет считаться строкой 1, а затем '\n'
будет считаться строкой 2. См., Что я использую scanf %c
для чтения ответа Y/N, но более поздний ввод пропускается. из справочника comp.lang.c.
Что касается предлагаемых решений, см. (Опять же из часто задаваемых вопросов по comp.lang.c):
которые в основном утверждают, что единственный переносимый подход:
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
Ваш цикл getchar() != '\n'
работает, потому что как только вы вызываете getchar()
, возвращаемый символ уже был удален из входного потока.
Кроме того, я чувствую себя обязанным препятствовать вам полностью использовать scanf
: почему все говорят, что не использовать scanf
? Что я должен использовать вместо этого?
Ответ 2
Вы можете сделать это (также) следующим образом:
fseek(stdin,0,SEEK_END);
Ответ 3
Строки:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
;
не читает только символы перед линией перевода строки ('\n'
). Он считывает все символы в потоке (и отбрасывает их) вплоть до следующего перевода строки (или EOF встречается). Чтобы тест был истинным, он должен сначала прочитать строку перевода; поэтому, когда цикл останавливается, строка возвращает последний символ, но он был прочитан.
Что касается того, почему он считывает перевод строки вместо возврата каретки, это потому, что система перевела возврат в строку. Когда нажата клавиша ввода, которая сигнализирует о конце строки... но поток содержит линейный канал, а не обычный маркер конца строки для системы. Это может быть зависимым от платформы.
Кроме того, использование fflush()
во входном потоке не работает на всех платформах; например, обычно это не работает в Linux.
Ответ 4
Портативный способ очистки до конца строки, которую вы уже пытались прочитать частично:
int c;
while ( (c = getchar()) != '\n' && c != EOF ) { }
Это считывает и отбрасывает символы, пока не получит \n
, который сигнализирует о конце файла. Он также проверяет на EOF
, если входной поток закрывается до конца строки. Тип c
должен быть int
(или больше), чтобы иметь возможность удерживать значение EOF
.
Нет портативного способа узнать, есть ли еще строки после текущей строки (если их нет, тогда getchar
будет блокировать вход).
Ответ 5
Но я не могу объяснить, как это работает? Потому что в выражении while мы используем getchar() != '\n'
, то есть читаем любой отдельный символ, кроме '\n'
? если это так, во входном буфере по-прежнему остается символ '\n'
??? Я что-то недопонимаю??
Вещь, которую вы, возможно, не осознаете, заключается в том, что сравнение происходит после того, как getchar()
удаляет символ из входного буфера. Поэтому, когда вы достигаете '\n'
, он потребляется, а затем вы выходите из цикла.
Ответ 6
вы можете попробовать
scanf("%c%*c", &ch1);
где% * c принимает и игнорирует новую строку
еще один метод
вместо fflush (stdin), который вызывает поведение undefined, вы можете написать
while((getchar())!='\n');
не забывайте точку с запятой после цикла
Ответ 7
unsigned char a=0;
if(kbhit()){
a=getch();
while(kbhit())
getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;
-или -
используйте, возможно, используйте _getch_nolock()
..???
Ответ 8
У меня возникла проблема с попыткой реализовать решение
while ((c = getchar()) != '\n' && c != EOF) { }
Я размещаю небольшую корректировку "Code B" для всех, у кого может быть такая же проблема.
Проблема заключалась в том, что программа заставляла меня ловить символ "\n", независимо от символа ввода, вот код, который дал мне проблему.
Код A
int y;
printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
continue;
}
printf("\n%c\n", toupper(y));
и настройка заключалась в том, чтобы "уловить" символ (n-1) непосредственно перед вычислением условного выражения в цикле while, вот код:
Код 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));
Возможное объяснение состоит в том, что для цикла while для прерывания он должен присвоить значение "\n" переменной y, поэтому это будет последнее назначенное значение.
Если я пропустил что-то с объяснением, код A или код B, пожалуйста, скажите мне, я едва новичок в c.
надеюсь, что это поможет кому-то
Ответ 9
Короткие, портативные и объявленные в stdio.h
stdin = freopen(NULL,"r",stdin);
Не зависает в бесконечном цикле, когда нет ничего на stdin, чтобы скрыть как следующая хорошо известная строка:
while ((c = getchar()) != '\n' && c != EOF) { }
Немного дороже, поэтому не используйте его в программе, которая должна многократно очищать буфер.
Украл у коллеги :)
Ответ 10
char choice;
do{
printf("\n *");
printf("\n Do you want to continue? (y/n) ");
choice = getchar();
if(getchar() != '\n'){
fflush(stdin);
}
}while( choice != 'n' );
Ответ 11
Еще одно решение, не упомянутое еще, - использовать: rewind (stdin);