По умолчанию стандартный ввод и стандартный вывод буферизуются. Это означает, что они накапливают партии символов и отправляют их сразу для эффективности. Как правило, пакет сохраняется до тех пор, пока в буфере не останется места или пока в потоке не появится новая строка или EOF.
Когда вы вызываете getchar()
, вы запрашиваете символы из стандартного ввода. Предположим, вы набираете A
, этот символ сохраняется в буфере, а затем система ожидает дальнейшего ввода. Если вы наберете B
, этот символ будет помещен в буфер следующим. Возможно, после этого вы нажмете Enter, и в буфер будет помещена новая строка. Но новая строка также прерывает процесс буферизации, поэтому первоначальный вызов getchar()
возвращает первый символ в буфере (A
). На следующей итерации вы снова вызываете getchar()
, и он немедленно возвращает следующий символ в буфере (B
). И так далее.
Таким образом, дело не в том, что ваш цикл while выполняется до тех пор, пока вы не закончите строку, а в том, что первый вызов getchar()
(когда буфер пуст) ожидает, пока он не заполнит буфер или не увидит новую строку.
Когда вы чередуете функции вывода, такие как putchar()
, большинство библиотек времени выполнения C будут «сбрасывать» стандартный ввод, когда вы делаете что-то, что отправляет данные в стандартный вывод (и наоборот). (Намерение состоит в том, чтобы убедиться, что пользователь увидит приглашение до того, как программа будет ожидать ввода.) Вот почему вы начали наблюдать другое поведение, когда добавили вызовы putchar()
.
Вы можете вручную очистить буфер, используя функцию flush()
. Вы также можете контролировать размер буфера, используемого стандартными потоками, используя setvbuf()
.
Как отметил Хан Пассант в комментариях, новая строка не «завершает поток». Чтобы получить EOF на stdin, вы должны нажать Ctrl+D (или, в некоторых системах, Ctrl+Z). EOF также очищает буфер. Если вы перенаправили файл или вывод из другой программы на стандартный ввод, EOF произойдет, как только этот ввод будет исчерпан.
Хотя это правда, что K&R C очень стар, и даже ANSI C сегодня не так распространен, как раньше, все, что касается буферизации с помощью stdin и stdout, фактически одинаково в текущих стандартах и даже в C++. Я думаю, что единственное существенное изменение заключается в том, что стандарты C теперь явно указывают на желательность того, чтобы stdin и stdout приводили к сбросу другого.
person
Adrian McCarthy
schedule
18.04.2016
CR
(он же возврат каретки) не завершает поток. - person too honest for this site   schedule 18.04.2016stdout
должен сбрасываться, когда вы читаете изstdin
. - person EOF   schedule 18.04.2016restrict
. Нарушение строгого алиасинга в C90, но не в C99 с помощью ключевого слова ограничения. Но это не строго одна и та же программа. - person Leandros   schedule 18.04.2016