Где `getchar ()` хранит пользовательский ввод? - PullRequest
7 голосов
/ 17 июня 2009

Я начал читать " Язык программирования C " (K & R), и у меня есть сомнения по поводу функции getchar().

Например, этот код:

#include <stdio.h>

main()
{
  int c;

  c = getchar();
  putchar(c);
  printf("\n");   
}

Ввод toomanychars + CTRL + D (EOF) печатает только t. Я думаю, что это ожидаемо, так как это первый введенный персонаж.

Но тогда этот другой кусок кода:

#include <stdio.h>

main()
{
  int c;

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

Набор текста toomanychars + CTRL + D (EOF) Печать toomanychars.

Мой вопрос: почему это происходит, если у меня только одна переменная char? где хранятся остальные символы?

EDIT:

Спасибо всем за ответы, я начинаю получать их сейчас ... только один улов:

Первая программа завершается, когда ей передается CTRL + D , в то время как вторая печатает всю строку, а затем ждет большего ввода пользователя. Почему он ждет другую строку и не выходит как первая?

Ответы [ 7 ]

9 голосов
/ 17 июня 2009

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

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

Последовательные вызовы getchar будут получать последовательные символы, поступающие со входа.

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

5 голосов
/ 17 июня 2009

Он обрабатывает входной поток как файл. Это как если бы вы открыли файл, содержащий текст «toomanychars», и прочитали или вывели его по одному символу за раз.

В первом примере, при отсутствии цикла while, вы открываете файл и читаете первый символ, а затем выводите его. Однако второй пример будет продолжать читать символы, пока не получит сигнал конца файла (ctrl+D в вашем случае), как если бы он читал из файла на диске.


В ответ на ваш обновленный вопрос, какую операционную систему вы используете? Я запустил его на своем ноутбуке с Windows XP, и он работал нормально. Если я нажму Enter, он распечатает то, что у меня было до сих пор, создаст новую строку и затем продолжит. (Функция getchar() не возвращается, пока вы не нажмете ввод, то есть когда в буфере ввода ничего нет, когда он вызывается). Когда я нажимаю CTRL+Z (EOF в Windows), программа завершается. Обратите внимание, что в Windows EOF должен находиться в отдельной строке, чтобы в командной строке он считался EOF. Я не знаю, имитируется ли это поведение в Linux или какой-либо другой системе, которую вы используете.

4 голосов
/ 17 июня 2009

Что-то здесь буферизовано. например stdout FILE *, в который пишет putchar, может быть line.buffered. Когда программа завершится (или встретит новую строку), такой ФАЙЛ * будет fflush () 'и вы увидите вывод.

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

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

int main() {
  int c;
   while((c = getchar()) != EOF) {
     if(c != '\n')
        putchar(c);
   }
    return 0;
}

Попробуйте ввести предложение в вашу программу и нажмите Enter. И сделайте то же самое, если вы закомментируете if (c! = '\ n') Может быть, вы можете определить, буферизуются ли ваш вход, выход или оба. Это становится более интересным, если вы запустите выше, как: ./mytest | ./mytest

(В качестве дополнительного комментария обратите внимание, что CTRD + D не является символом и не является EOF. Но в некоторых системах это приведет к закрытию входного потока, что снова повысит EOF для любого, кто пытается прочитать из потока.)

3 голосов
/ 17 июня 2009

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

2 голосов
/ 17 июня 2009

Вы используете только переменную c, чтобы содержать каждый символ по одному.

Как только вы отобразите первый символ (t), используя putchar(c), вы забудете о значении c, присвоив следующий символ (o) переменной c, заменив предыдущий значение (t).

1 голос
/ 17 июня 2009

код функционально эквивалентен

main(){
  int c;
  c = getchar();
  while(c != EOF) {
    putchar(c);
    c = getchar();
  }
}

вам может показаться, что эту версию легче понять. единственная причина для того, чтобы поместить назначение в условное выражение, состоит в том, чтобы не вводить дважды 'c = getchar ()'.

0 голосов
/ 03 мая 2011

Для вашего обновленного вопроса в первом примере читается только один символ. Это никогда не достигает EOF. Программа завершается, потому что после выполнения инструкции printf ей нечего делать. Это просто читает один символ. Печатает это. Ставит новую строку. И затем заканчивается, так как ему больше нечего делать. Он не читает более одного символа.

Принимая во внимание, что во втором коде getchar и putchar присутствуют внутри цикла while. При этом программа продолжает читать символы один за другим (как это делается в цикле), пока не достигнет символа EOF (^ D). В этот момент он соответствует c! = EOF, и поскольку условия не выполняются, он выходит из цикла. Теперь больше нет операторов для выполнения. Таким образом, программа завершается в этот момент.

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

...