getchar() в C завершается без нажатия Enter

Из моего предыдущего сообщения я узнал, что getchar() завершается только тогда, когда мы нажимаем Enter. Рассмотрим этот код:

#include<stdio.h>
main()
{
  getchar();
  getchar();
  getchar();
  getchar();
  getchar();


}

Я ожидал, что это будет работать так: я нажимаю клавишу 1, затем нажимаю Enter, затем клавишу 2 и клавишу Enter, затем клавишу 3 и клавишу Enter, затем клавишу 4 и клавишу Enter и, наконец, клавишу 5+Enter, теперь программа должна завершиться. Это не то, что происходит на самом деле. Происходит следующее: я нажимаю клавишу 1, затем нажимаю Enter, затем клавишу 2 и клавишу Enter, затем клавишу 3 и клавишу Enter, программа в конечном итоге завершается!

  • Почему не работают последние два getchar()?

Еще одна странная вещь, которую я заметил, заключается в том, что если я делаю: key1,key2,key3,key4+Enter, программа завершается. Например. Если я последовательно нажму q,w,e и r, а затем Enter, программа завершится.

  • Почему не все getchar() запрашивают ввод? Означает ли это, что getchar() принимает любой другой ключ в качестве Enter? Но тогда следующий ключ принимается в качестве ввода для следующего getchar()?

Рассмотрим другой код:

#include<stdio.h>
main()
{

  int c=getchar();
  int d=getchar();
  int e=getchar();
  printf("2 getchar are remaining\n");
  int f=getchar();
  int g=getchar();
  printf(" c is %d, d is %d, e is %d, f is %d and g is %d",c,d,e,f,g);

} 

Я ввожу: ABCDEFG, затем Enter. Строка осталось 2 getchar() должна быть напечатана, как только я нажму C или D. Но она напечатана наконец, это означает, что все getchar() выполняются одновременно - это странно.

  • Разве программа не выполняется построчно? т.е. после третьего getchar должна работать функция printf(). Но это работает, наконец, когда все getchar() выполняются.

person user31782    schedule 06.12.2014    source источник
comment
Ввод буферизуется и недоступен для getchar(), пока вы не нажмете клавишу Enter. Этот ключ также возвращается. Небуферизованный ввод обычно доступен в ЭЛТ, но не является стандартным.   -  person Hans Passant    schedule 06.12.2014


Ответы (4)


Неправда, что getchar() завершается после нажатия клавиши ввода. getchar() завершается всякий раз, когда есть символы для чтения. Эта разница значительна: см., например, если вы используете свою программу со стандартным вводом, перенаправленным в файл:

$ hexdump -C abcd_file 
00000000  61 62 63 64 65                                    |abcde|
00000005

$ ./in < abcd_file 
$

Обратите внимание, что «abcd_file» — это файл, который содержит «abcde», без новой строки, и ваша программа завершается, не требуя новой строки. Это потому, что файл все время предоставляет символы и не ждет новой строки.

С другой стороны, обычные терминалы или эмуляторы терминалов имеют режим работы, который называется «каноническим режимом». Канонический режим означает, что терминал поддерживает «средства обработки командной строки» и не будет сигнализировать о доступном символе, пока пользователь не нажмет ENTER. Вот откуда берется неправильная история «getchar() ждет ENTER». Вы можете переключить свой терминал из канонического режима и увидеть, как он извлекает все символы без необходимости нажимать клавишу ввода:

$ stty -icanon; ./in; stty icanon
ggggg$

В этом случае 5 символов без ввода заставили программу завершиться.

Наконец, причина того, что getchar() выглядит так, будто возвращается раньше, заключается в том, что она также возвращает символы ENTER. Итак, "a\nb\nc\n" - это 6 символов, первые 5 возвращаются функцией getchar(), шестой удаляется из очереди терминала после завершения программы. Ввод «abcd\n» также означает, что getchar() будет немедленно доступен для 5 последовательных чтений, потому что в очереди терминала хранится 5 символов.

http://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html#Noncanonical-Input

person hdante    schedule 06.12.2014
comment
Я использую ОС Windows-7. Как я могу временно вывести свой терминал из канонического режима? - person user31782; 07.12.2014

Что касается вашего первого вопроса, клавиша ввода — это символ, который getchar может обрабатывать и возвращать. Поэтому, если вы наберете два символа и нажмете клавишу ввода, вам придется вызвать getchar три раза, чтобы очистить буфер ввода. Помните, что getchar берет клавишу не с клавиатуры, а из буфера ввода. Итак, если вы вставите пять символов в свой входной буфер, например. abcdenter, вам придется вызвать getchar пять раз, чтобы получить все это, и первый не вернется, пока вы не нажмете enter.

Это также объясняет ваш второй вопрос. Вызовы getchar выполняются последовательно, а не одновременно, после нажатия enter, но первый вызов не выполняется до тех пор.

Вы можете прочитать об отключении буферизации ввода.

person dsolimano    schedule 06.12.2014
comment
Означает, что когда я нажимаю Enter после последовательного написания символов ABCD, затем компилятор фактически запускает программу. Он дает первые 4 символа первым четырем getchar(), и если 5-й символ является вводом, то он передается последнему getchar(). - person user31782; 07.12.2014
comment
Как инициируется этот входной буфер? Когда компилятор видит первый вызов getchar(), он запускает входной буфер. И пока я не нажму Enter, входной буфер продолжает принимать символы. - person user31782; 07.12.2014
comment
Входной буфер управляется ОС/терминалом, а не компилятором. Компилятор не запускает программу, компилятор компилирует программу. ОС запускает выполнение программы, а потом getchar превращается, наверное, в блокирующий системный вызов, если хотите что-то погуглить. - person dsolimano; 07.12.2014

Разве программа не выполняется построчно? т.е. после третьего getchar должна работать функция printf(). Но это работает, наконец, когда все getchar() выполняются.

Он выполняется построчно, однако клавиша ENTER является допустимым вводом для getchar(), поэтому он будет считывать свое значение ASCII. Не могу сказать больше, потому что это значение зависит от системы.

person senex    schedule 06.12.2014

getchar() принимает каждый введенный символ за символом. Он не ждет нажатия клавиши ввода. Запустите программу, приведенную ниже, и проверьте вывод, чтобы получить более качественную картину.

 #include <stdio.h>
    int main( ) {

       int c;
       int i;
       printf( "Enter a value :");
       i = getchar();
       printf( "Enter a value :");
       c = getchar();
       printf( "\nYou entered: ");
       putchar( c );
       printf( "\nYou entered: ");
       putchar(i);
       return 0;
    }

ВЫВОД: (клавиша Enter нажата после ввода одного символа)

Enter a value :1
Enter a value :
You entered:

You entered: 1
Process returned 0 (0x0)   execution time : 3.183 s
Press any key to continue.

ВЫВОД: (ВВОД вводится до нажатия клавиши ввода)

Enter a value :12
Enter a value :
You entered: 2
You entered: 1
Process returned 0 (0x0)   execution time : 5.389 s
Press any key to continue.

Надеюсь это поможет!

person Mithun Chakravarthy    schedule 23.02.2016