Почему этот код печатает строки, а не одиночные символы - PullRequest
0 голосов
/ 17 марта 2019
#include <stdio.h>
int main()
{
  int c;
  while((c=getchar())!=EOF)
  putchar(c);
  return 0;
}

В моем ограниченном воздействии на C, пока C! = EOF, будет выполнено условие while, которое, по сути, выведет c, а затем будет ждать следующего символа и попытаться проверить, что нарушает или не нарушаетсостояние.Следовательно, для каждого введенного символа ввод будет выполняться.Однако, когда я запустил исполняемый файл, казалось, что оператор print будет работать только тогда, когда я нажму на новую строку (Enter), и у него будет какой-то буфер, который будет печатать всю строку на входе.Я не вижу никакого буфера в коде, который будет содержать символы до тех пор, пока не будет нажата новая строка, так что же здесь делается?Где хранятся эти символы до тех пор, пока не будет нажата новая строка?

Ответы [ 3 ]

2 голосов
/ 17 марта 2019

При таком чтении с консоли ваша программа фактически не получает никакого ввода, пока вы не нажмете клавишу ввода, а затем прочитает и обработает всю строку сразу.

Ваша программа не знает, чтоэти символы существуют даже до тех пор, пока вы не нажмете ввод, после чего они будут отправлены в буфер stdin.Отсюда ваш цикл будет читать и печатать каждый символ (включая новую строку) до тех пор, пока либо буфер не станет пустым (что означает, что он будет ждать ввода большего числа), либо пока не будет достигнут конец файла.

1 голос
/ 20 марта 2019

Функции getchar() и putchar() являются частью пакета stdio, который выполняет буферизованный ввод / вывод.

Это означает, что, несмотря на количество символов, которое вы на самом деле запрашиваете (один только в вашем случае), механизм буферизации заставляет символы ждать в буфере, пока весь буфер (или одна строка, в случае, если stdin не получен из tty устройство) заполнено.

То, что здесь происходит, заключается в том, что при первом getchar() запрашивается полное заполнение буфера, и оно только частично заполняется введенной вами строкой ввода. После этого все вызовы getchar() получают отдельные символы из буфера, пока он снова не станет пустым, и в этот момент запрашивается другой полный буфер.

Это сделано для того, чтобы обработка одного символа была эффективным способом обработки. Это также происходит на выходе. Функция putchar() заполняет только буфер до тех пор, пока он не будет полностью заполнен (или, если ваш выходной канал подключен к tty-устройству, пока вы не запросите вывод символа \n), и когда это произойдет, будет выведен полный буфер к файлу / устройству.

Кроме того, драйвер терминала во всех разновидностях Unix работает в линейном режиме, что означает, что пока вы не нажмете клавишу <ENTER>, вы ничего не отправите в программу. Это позволит вам исправить ошибки, допущенные при вводе, с помощью клавиш стирания (backspace) и / или клавиш kill (Cntrl-U). Это моделируется в консольных приложениях Windows, поэтому вам, вероятно, понадобится устройство вывода в необработанном режиме, прежде чем можно будет вводить символьным способом.

Если вы хотите, чтобы ваша программа считывала по одному символу за раз, вам нужно обойти буферы stdio (через вызов функции setbuf(NULL) или используя системный вызов read(2) для чтения одного символа, который может быть сделано с:

char c;
int res = read(0, &c, 1);
if (res < 0) { /* error */
    ...
} else if (res == 0) { /* EOF in input */
    ...
} else { /* 1, as you requested only one char */
    ... /* one character was read. */
}

) и перевести драйвер терминала в необработанный режим (с помощью вызовов tcsetattr() и tcgetattr(), см. Справочную страницу termios(4) для получения подробной информации о том, как это сделать) перед тем, как приступить к чтению. В этом случае вы должны вернуть состояние терминала в линейный режим перед завершением программы, иначе у вас возникнут проблемы.

1 голос
/ 17 марта 2019

Буферизация происходит при чтении данных и при записи данных.

stdin и stdout, независимо могут быть символ , строка или полностью в буфере.

В вашем обычном случае, оба строки буферизированы.

Входные данные не передаются getchar() до тех пор, пока не будет нажата Enter ('\n'). (Можете ли вы вводить пробел обратно?) И вывод не отображается, пока не будет напечатано '\n'.

...