Как очистить входной буфер в 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 = %dn", ch1, ch1);
  printf("ch2=%c, ASCII code = %dn", 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' );
    }
    

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

11 61

11 ответов:

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

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

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

Что касается предлагаемые решения см. (Опять же из комп.ленг.C FAQ):

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

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

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

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

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

fseek(stdin,0,SEEK_END);

строки:

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

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

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

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

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

int c;

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

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

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

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

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

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

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

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

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

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

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

unsigned char a=0;
if(kbhit()){
    a=getch();
    while(kbhit())
        getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;

или

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

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

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

я публикую небольшую корректировку "код B" для тех, кто, возможно, имеет ту же проблему.

проблема заключалась в том, что программа заставляла меня ловить символ '\n', независимо от символа ввода, вот код, который дал мне проблему.

Код

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.

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

короткий, портативный и объявленный в stdio.h

stdin = freopen(NULL,"r",stdin);

не зависает в бесконечном цикле, когда на stdin нет ничего, чтобы смыть, как следующая хорошо известная строка:

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

немного дорого, поэтому не используйте его в программе, которая должна повторно очистить буфер.

украл у коллеги :)

char choice;
do{
    printf("\n *");
    printf("\n Do you want to continue? (y/n) ");
    choice = getchar();
    if(getchar() != '\n'){
        fflush(stdin);
    }
}while( choice != 'n' );

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