Как очистить входной буфер в C? - PullRequest
67 голосов
/ 26 октября 2011

У меня есть следующая программа:

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?

Далее автор предложил 2 способа решения таких проблем:

  1. использовать fflush()

  2. написать такую ​​функцию:

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

Thisкод работал на самом деле.Но я не могу объяснить себе, как это работает?Поскольку в операторе while мы используем getchar() != '\n', это означает чтение любого отдельного символа, кроме '\n'?если так, во входном буфере все еще остается символ '\n'?

Ответы [ 11 ]

74 голосов
/ 26 октября 2011

Программа не будет работать должным образом, поскольку в строке 1, когда пользователь нажимает клавишу Enter, она оставляет в буфере ввода 2 символа: клавишу ввода (код ASCII 13) и \ n (код ASCII 10).Поэтому в строке 2 он будет читать \ n и не будет ждать ввода пользователем символа.

Поведение, которое вы видите в строке 2, является правильным, но это не совсем правильное объяснение.,С потоками текстового режима не имеет значения, какие окончания строки использует ваша платформа (возврат каретки (0x0D) + перевод строки (0x0A), пустой CR или пустой LF).Об этом позаботится библиотека времени выполнения C: ваша программа увидит только '\n' для новых строк.

Если вы наберете символ и нажмете ввод, то этот символ ввода будет прочитан в строке 1, итогда '\n' будет прочитано в строке 2. См. Я использую scanf %c, чтобы прочитать ответ Y / N, но позже ввод пропускается. из часто задаваемых вопросов comp.lang.c.

Что касается предлагаемых решений, см. (Снова из FAQ по comp.lang.c):

, которые в основном утверждают, что единственный переносимый подходсделать:

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

Ваш цикл getchar() != '\n' работает, потому что после вызова getchar() возвращенный символ уже был удален из входного потока.

Кроме того, я чувствую себя обязаннымотговаривать вас от использования scanf полностью: Почему все говорят, что не следует использовать scanf?Что я должен использовать вместо этого?

37 голосов
/ 17 марта 2012

Вы можете сделать это (также) следующим образом:

fseek(stdin,0,SEEK_END);
11 голосов
/ 26 октября 2011

Строки:

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

не читает только символы до перевода строки ('\n').Он читает все символы в потоке (и отбрасывает их) вплоть до , включая следующий перевод строки (или EOF встречается).Чтобы тест был верным, он должен сначала прочитать перевод строки;поэтому, когда цикл останавливается, перевод строки был последним прочитанным символом, но он был прочитан.

Что касается того, почему он читает перевод строки вместо возврата каретки, то это потому, что система преобразовала возврат в перевод строки.,Когда нажата клавиша enter, это сигнализирует об окончании строки ... но вместо этого поток содержит перевод строки, поскольку это обычный маркер конца строки для системы.Это может зависеть от платформы.

Кроме того, использование fflush() во входном потоке работает не на всех платформах;например, он обычно не работает в Linux.

10 голосов
/ 28 сентября 2014

Портативный способ очистить до конца строки, которую вы уже пытались прочитать частично:

int c;

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

Это читает и отбрасывает символы, пока не получит \n, который сигнализирует об окончании файла. Он также проверяет EOF в случае, если входной поток закрывается до конца строки. Тип c должен быть int (или больше), чтобы иметь возможность хранить значение EOF.

Нет портативного способа узнать, есть ли еще строки после текущей строки (если их нет, getchar заблокирует для ввода).

8 голосов
/ 26 октября 2011

Но я не могу объяснить себе, как это работает? Поскольку в операторе while мы используем getchar() != '\n', это означает чтение любого отдельного символа, кроме '\n' ?? если так, во входном буфере все еще остается символ '\n' ??? Я что-то неправильно понимаю?

Вы можете не осознавать, что сравнение происходит после того, как getchar() удаляет символ из входного буфера. Таким образом, когда вы достигаете '\n', он расходуется, и затем вы выходите из цикла.

6 голосов
/ 12 апреля 2015

вы можете попробовать

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

, где% * c принимает и игнорирует новую строку

еще один метод вместо fflush (stdin), который вызывает неопределенное поведение, которое вы можете написать

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

не забывайте точку с запятой после цикла while

4 голосов
/ 26 марта 2018

Другое решение, еще не упомянутое, состоит в использовании перемотка назад (STDIN);

1 голос
/ 20 апреля 2017

Я столкнулся с проблемой, пытаясь реализовать решение

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

Я публикую небольшую корректировку «Код 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.

надеюсь, это кому-нибудь поможет

1 голос
/ 19 августа 2014
unsigned char a=0;
if(kbhit()){
    a=getch();
    while(kbhit())
        getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;

-или-

использовать возможно использовать _getch_nolock() .. ???

0 голосов
/ 12 февраля 2018
char choice;
do{
    printf("\n *");
    printf("\n Do you want to continue? (y/n) ");
    choice = getchar();
    if(getchar() != '\n'){
        fflush(stdin);
    }
}while( choice != 'n' );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...