Буферный ввод 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: // программа 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;
}
Я хочу понять, когда драйвер терминала фактически передает входную строку программе. Предположим, мой ввод - это строка "это тест", и я нажимаю клавишу ввода, и вот как работают вышеупомянутые коды:
код 1: выводит "t" (и программа заканчивается)
код 2: выводит "это тест", переходит на следующую строку (потому что он также выводит нажатую клавишу ввода) и снова ждет ввода.
код 3: ничего не выводит для указанной выше строки, за которой следует ввод. Мне нужно нажать Ctrl+D для вывода вывода (вывод 15 4 3 1)
1) Почему в случае кода 3 мне нужно явно нажимать Ctrl+D (EOF), чтобы входные данные были отправлены в мою программу? Другими словами, почему моя входная строка была отправлена в мою программу в случае кода 1 и кода 2 после того, как я нажал клавишу ввода? Почему он также не попросил EOF?
2) Кроме того, в случае кода 3, если я не нажимаю ввод после строки ввода, мне нужно дважды нажать Ctrl+D, чтобы отобразить вывод. Почему это так?
РЕДАКТИРОВАТЬ:
Для другого ввода скажите "TESTING^D", вот как работают приведенные выше коды:
1) выводит "Т" и заканчивается
2) выводит "TESTING" и ждет большего ввода
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 ответ
Основная информация:
В случае кода 2: вам также нужно сделать Ctrl+D, чтобы выйти.
На самом деле EOF достигается нажатием ctrl+D, так что условие вашего цикла while говорит:
- получить ввод с клавиатуры
- сохранить его в к
- если вход не был равен 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, и пропустить, чтобы продолжить выполнение остальной части кода.