Подтвердить что ты не робот

Как очистить входной буфер в 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?

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

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

  • напишите такую ​​функцию:

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

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

4b9b3361

Ответ 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);