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

#c #getchar #putchar

#c #getchar #putchar

Вопрос:

Я пытаюсь понять, как драйвер терминала работает в сочетании с 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:
// программа barebones, которая эмулирует функциональность команды 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;
}
  

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

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

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

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

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

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

Редактировать:

Для другого ввода скажите «TESTING ^ D», вот как работают приведенные выше коды:

1) выводит «T» и завершает

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, когда он находится на новой строке. Но в случае моего ввода «TESTING ^ D» он работает нормально, даже если ^ D находится в той же строке, что и остальные входные данные. Каким может быть возможное объяснение этого?

Комментарии:

1. Обращаясь к вашему последнему вопросу: в связанной статье Википедии не указан источник для этого. Насколько я помню, ctrl d отправляет EOF , если буфер терминала очищен, а в противном случае он очищает буфер. Новая строка также очищает буфер. К сожалению, я тоже не могу найти ссылку на это в данный момент. HTH

2. @mafso Спасибо за информацию.

Ответ №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 после того, как я нажал enter? Почему он также не запрашивал EOF?

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

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

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

Комментарии:

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

2. ctrl D с вводом сигнализирует программе обработать ввод. Enter добавляет символ n и отправляет ввод в программу. Но обратите внимание, что ctrl D без ввода перед этим вернет EOF @Karan

3. 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 @Каран

4. Поддержано! Ссылка на Википедию гласит, что Ctrl D должно быть началом строки, чтобы драйвер преобразовал ее в EOF. Но когда я ввожу «TESTING ^ D ^ D» в код 3, моя программа выдает вывод и завершает работу, даже если второй ^ D находится в той же строке, что и ввод. Чего мне здесь не хватает?