Что повторяется через стандартный ввод, когда getchar() находится в цикле?

Этот первый пример персонажа K&R поставил меня в тупик.

#include <stdio.h>
/* copy input to output; 2nd version */
main()
{
  int c;
  while ((c = getchar()) != EOF)
    putchar(c);
}

Например, ввод abcd напечатает abcd. Я бы ожидал, что он напечатает только a, потому что строка из стандартного ввода никогда не сохраняется полностью внутри этой программы, и даже если бы здесь ничего не было, она бы перебирала ее.

Я не понимаю, как getchar() перебирает стандартный ввод, чтобы перейти к следующему символу. Это функция стандартного ввода или C?

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

malkaroee 17.05.2022 13:03

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

Lundin 17.05.2022 13:05

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

Support Ukraine 17.05.2022 13:15

@malkaroee Спасибо! Я искал указатели чтения и нашел Документы IBM, который говорит, что getchar() читает, а затем перемещает позицию потока, и документ окон, который рисовал достойную картину того, как осуществляется доступ к потоку. Я проверил эту функциональность итерации, написав getchar и putchar в последовательности N раз вне цикла, и, как и ожидалось, он напечатал строку до N символов. Дикий!

GBE 17.05.2022 13:42

Цитата @GBE: «... и, как и ожидалось, он напечатал строку до N символов. Wild!» ну, это было бы еще более "дико", если бы этого не было ;-)

Support Ukraine 17.05.2022 13:45

@GBE И для удовольствия вы даже можете добавить 5-секундный сон между каждым getchar. Это по-прежнему будет работать... кто-то позаботится о буферизации символов для вас. Никакой магии.

Support Ukraine 17.05.2022 13:49
getcharявляется итерация
user253751 17.05.2022 14:02

@Lundin функция main() без return не соответствует стандарту C. О чем ты говоришь? Функция main без return была совершенно законно во всех версиях C, начиная с C99.

Steve Summit 17.05.2022 14:24

@SteveSummit Если вы собираетесь спорить об этом, укажите правильные источники. ISO 9899:1990 6.6.6.4 «если выполняется оператор return без выражения и значение вызова функции используется вызывающей стороной, поведение не определено. Достижение }, которое завершает функцию, эквивалентно выполнению оператора return без выражение."

Lundin 17.05.2022 14:30

@Lundin Существует явное исключение для функции с именем main, как подробно цитируется в вопрос, с которым я связался.

Steve Summit 17.05.2022 14:55

@SteveSummit Да в C99 и выше. Но K&R не был написан для C99, и main() не будет компилироваться в C99. Так что это всегда было неправильно, как ни крути.

Lundin 17.05.2022 14:56

@Lundin Тогда согласен не согласиться.

Steve Summit 17.05.2022 14:59
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
12
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы вводите "abcd"

It reads 'a', checks if it is not equal to EOF. 
If not prints 'a'
Then you go to the beginning of the loop:
It reads 'b', checks if it is not equal to EOF. 
If not prints 'b'
Then you go to the beginning of the loop:
.....

It returns EOF, checks if it is not equal to EOF. 
As it is equal it terminates the wile loop

getchar()нет "читает" EOF. getchar обнаруживает, что поток исчерпан, и возвращает EOF, чтобы указать, что вы достигли конца файла.
William Pursell 17.05.2022 13:27

@WilliamPursell Это шалость. Стандарт C говорит: «Если поток находится в конце файла, устанавливается индикатор конца файла для потока, и getchar возвращает EOF».

Lundin 17.05.2022 13:32

@Lundin Это совсем не мудрствование. Существует мифология, что EOF — это символ, который на самом деле присутствует в потоках. «getchar возвращает EOF» на очень отличается от «getchar читает EOF», и я рад видеть, что ответ был отредактирован, чтобы удалить эту фразу.

William Pursell 17.05.2022 13:37

@WilliamPursell Streams — это довольно мифологическая концепция для начала, это слой абстракции над простым входным буфером. В стандарте C не упоминается, как библиотечные функции могут узнать, пуст ли поток или нет. Очень вероятно, прочитав счетчик размера, но это не указано.

Lundin 17.05.2022 13:45
Ответ принят как подходящий

getchar читает из поток. Вот что такое stdin. Поток — это структура данных, которая представляет собой последовательность данных, которые считываются или куда-то записываются. Поток не похож на одну переменную. Это не похоже на массив. Это не то, что вы «перебираете». Это вам что-то получить от (или положить).

Вы можете думать об этом как о колоде карт, которую вы используете в игре. То есть вы можете проделывать такие операции, как: посмотреть карту сверху колоды, взять карту сверху колоды и положить в руку, взять N карт сверху колоды и положить их в свою рука.

Итак, когда вы видите код вроде

while ((c = getchar()) != EOF)
    putchar(c);

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

while ( I try to take a card from the top of the deck and I do get one )
    put the card in my hand;

Как правило, вы можете взять довольно много карт. Однако, в конце концов, вся колода будет израсходована, и ваш цикл остановится.

Звонок getchar не похож на звонок sqrt(4). Если вы позвоните sqrt(4) несколько раз, вы каждый раз будете получать один и тот же ответ. Но если вы позвоните getchar() несколько раз, вы каждый раз будете получать ответ другой. (Формально мы говорим, что getchar имеет штат, а его вызов имеет побочный эффект. В частности, каждый раз, когда вы вызываете getchar, он имеет побочный эффект постоянного удаления одного символа из потока, то есть обновления состояния потока. чтобы зафиксировать тот факт, что был прочитан еще один символ.)

P.S. Аналогия с колодой карт не идеальна. С обычным потоком данных невозможно сделать что-то вроде взятия карты из середины колоды или перетасовки колоды. Но вы можете, как правило, положить одну карту обратно на верх колоды (это называется ungetc в C). Кроме того, внутри, когда колода становится низкой, если вы читаете из файла, механизм stdio может взять кучу новых карт (еще один блок из файла) и вставить их в конец колоды.

Другие вопросы по теме