буферизованный ввод getchar, EOF и драйвер терминала

Я пытаюсь понять, как работает драйвер терминала в связке с getchar. Вот несколько примеров кода, которые я написал, читая KandR:

Код 1:

#include <stdio.h>

int main(){

  int c = getchar();
  putchar(c);


  return 0;

}

Код 2:

    #include <stdio.h>

    int main(){

    int c = EOF;

    while((c=getchar()) != EOF){
    printf("%c",c);
    }
    return 0;
}

Код 3: // базовая программа, которая эмулирует функциональность команды wc

    #include <stdio.h>
    #define IN 1
    #define OUT 0

    int main(){
      //nc= number of characters, ns = number of spaces, bl=number of newlines, nw=number of words
      int c = EOF,nc=0,nw=0,ns=0,nl=0, state = OUT;

      while((c=getchar())!=EOF){
        ++nc;
        if(c=='\n'){
          ++nl;
          state = OUT;
        }
        else if(c==' '){
          ++ns;
          state = OUT;
        }

        else{
          if(state == OUT){
          state = IN;
          ++nw;}
        }

      }

      printf("\n%d %d %d %d",nc,nw,ns,nl); 
return 0;
}

Я хочу понять, когда драйвер терминала фактически передает входную строку программе. Предположим, что я ввел строку «это тест», и я нажимаю ввод, тогда вот как работают вышеупомянутые коды:

код 1: выводит "t" (и программа завершается)

код 2: выводит «это тест», переходит к следующей строке (потому что он также выводит ввод, который я нажал) и снова ждет ввода.

код 3: ничего не выводит для приведенной выше строки, за которой следует ввод. Мне нужно нажать Ctrl+D для отображения вывода (выход 15 4 3 1)

1) Почему в случае кода 3 мне нужно явно нажимать Ctrl+D (EOF) для отправки ввода в мою программу? Другими словами, почему моя входная строка была отправлена ​​​​в мою программу в случае кода 1 и кода 2 после того, как я нажал клавишу ввода? Почему он также не запросил EOF?

2) Кроме того, в случае кода 3, если я не нажимаю ввод после входной строки, мне нужно дважды нажать Ctrl + D для отображения вывода. Почему это так?

ИЗМЕНИТЬ:

Для другого ввода скажите «ТЕСТИРОВАНИЕ ^ D», вот как работают приведенные выше коды:

1) выводит "Т" и заканчивается

2) выводит «ТЕСТИРОВАНИЕ» и ждет дополнительных входных данных

3) ничего не выводит, пока не будет нажата другая Ctrl+D. затем он выводит 7 1 0 0.

В случае этого ввода драйвер терминала отправляет входную строку в программу при получении Ctrl+D в случае кода 1 и кода 2. Означает ли это, что /n и Ctrl+D обрабатываются одинаково, т.е. они оба служат маркер для драйвера терминала для отправки ввода в программу? Тогда почему мне нужно дважды нажать Ctrl+D для второго случая?

Это http://en.wikipedia.org/wiki/End-of-file говорит, что драйвер преобразует Ctrl+D в EOF, когда он находится на новой строке. Но в случае моего ввода «ТЕСТИРОВАНИЕ ^ D» он работает нормально, даже если ^ D находится в той же строке, что и остальная часть ввода. Какое может быть возможное объяснение этому?


person user720694    schedule 15.06.2014    source источник
comment
Отвечая на ваш последний вопрос: в связанной статье Википедии не указан источник для этого. Насколько я помню, ctrl+d отправляет EOF, если буфер терминала сбрасывается, а в противном случае сбрасывает буфер. Новая строка также очищает буфер. К сожалению, я не могу найти ссылку на это в данный момент. ХТН   -  person mafso    schedule 15.06.2014
comment
@mafso Спасибо за информацию.   -  person user720694    schedule 04.07.2014


Ответы (1)


Общая информация:

В случае кода 2: вам также нужно нажать ctrl+D, чтобы выйти.

На самом деле EOF достигается нажатием Ctrl + D, так что ваше условие цикла while говорит:

  1. получить ввод с клавиатуры
  2. сохранить его в c
  3. если ввод не был равен EOF выполнить тело цикла while

EOF — это не что иное, как целое число -1, и этого можно добиться в терминале, нажав ctrl+D. Итак, взяв этот пример:

while((c=getchar()) != EOF){
   // execute code
}

printf("loop has exited because you press ctrl+D");

Условие продолжает принимать ввод, но останавливается, когда вы нажимаете ctrl+D, после чего продолжает выполнение остальной части кода.

Отвечаю на ваши вопросы:

1) Почему в случае кода 3 мне нужно явно нажимать Ctrl+D (EOF) для отправки ввода в мою программу? Другими словами, почему моя входная строка была отправлена ​​​​в мою программу в случае кода 1 и кода 2 после того, как я нажал клавишу ввода? Почему он также не запросил EOF?

В коде 2 и 3 (не только 3) вам нужно нажать Ctrl + D, потому что цикл while перестает принимать ввод с клавиатуры только тогда, когда он читает EOF. В коде 1 вы не зацикливаетесь, поэтому, когда вы вводите один или несколько символов, программа будет читать введенные символы, но сохранит только первый, затем распечатает его и завершит программу, поэтому в этом случае нет необходимости в EOF потому что вы не просите об этом нигде в любом состоянии.

2) Кроме того, в случае кода 3, если я не нажимаю ввод после входной строки, мне нужно дважды нажать Ctrl + D для отображения вывода. Почему это так?

Если вы начали печатать, когда программа ожидает ввода, то после ввода хотя бы одного символа вы нажимаете ctrl+D, это сообщит программе прекратить ввод и вернуть введенные символы. После этого, если вы снова нажмете ctrl+D без ввода какого-либо символа, это вернет EOF, который затем не будет удовлетворять условию цикла while и пропустит продолжение выполнения остальной части кода.

person CMPS    schedule 15.06.2014
comment
Итак, если я вас правильно понял, /n и Ctrl+D обрабатываются одинаково, то есть они оба служат маркером для драйвера терминала для отправки ввода в программу? Только когда Ctrl + D отправляется без текста, он обрабатывает его как EOF? В коде 1 и 2: когда я нажимаю /n или Ctrl + D после ввода, ввод становится доступным для putchar? - person user720694; 15.06.2014
comment
ctrl+D с вводом сигнализирует программе обработать ввод. Enter добавляет символ \n и отправляет ввод в программу. Но обратите внимание, что Ctrl + D без ввода, прежде чем он вернет EOF @Karan - person CMPS; 15.06.2014
comment
Block-reading functions return the number of bytes read, and if this is fewer than asked for, then the end of file was reached. en.wikipedia.org/wiki/End-of-file @Karan - person CMPS; 15.06.2014
comment
Проголосовал! Ссылка на википедию говорит, что Ctrl + D должен быть началом строки, чтобы драйвер мог преобразовать ее в EOF. Но когда я ввожу TESTING^D^D в код 3, моя программа выдает вывод и завершает работу, хотя второй ^D находится в той же строке, что и ввод. Что мне здесь не хватает? - person user720694; 15.06.2014