Почему этот цикл getchar() останавливается после ввода одного символа?

#include <stdio.h>

int main() {
    char read = ' ';

    while ((read = getchar()) != '\n') {
        putchar(read);
    }

    return 0;
}

Мой ввод f (за которым, конечно, следует ввод). Я ожидаю, что getchar() снова запросит ввод, но вместо этого программа завершается. Как так? Как я могу это исправить?


person Pieter    schedule 17.03.2010    source источник


Ответы (5)


Терминал иногда может немного сбивать с толку. Вы должны изменить свою программу на:

#include <stdio.h>

int main() {
    int read;
    while ((read = getchar()) != EOF) {
        putchar(read);
    }
    return 0;
}

Это будет читаться до тех пор, пока getchar не прочитает EOF (в большинстве случаев этот макрос расширяется до -1) с терминала. getchar возвращает int, поэтому вы должны преобразовать свою переменную в целое число, чтобы вы могли проверить наличие EOF. Вы можете отправить EOF со своего терминала в Linux с помощью ^D и, я думаю, в Windows с помощью ^Z (?).

Чтобы немного объяснить, что происходит. В вашей программе выражение

(read = getchar()) !='\n'

будет истинным до тех пор, пока из буфера не будет прочитано '\n'. Проблема в том, чтобы получить буфер для вашей программы, вы должны нажать Enter, что соответствует '\n'. Следующие шаги происходят, когда ваша программа вызывается в терминале:

~$\a.out

это запускает вашу программу

(empty line)                    

getchar() сделал системный вызов, чтобы получить ввод от терминала, и терминал берет на себя

f                   

вы сделали ввод в терминале. 'f' записывается в буфер и выводится обратно на терминал, ваша программа еще не знает о символе.

f
f~$                 

Вы нажимаете ввод. Ваш буфер теперь содержит 'f\n'. «Ввод» также сигнализирует терминалу, что он должен вернуться в вашу программу. Ваша программа читает буфер, находит f и выводит его на экран, а затем находит '\n' и немедленно останавливает цикл и завершает вашу программу.

Это было бы стандартным поведением большинства терминалов. Вы можете изменить это поведение, но это будет зависеть от вашей ОС.

person Lucas    schedule 17.03.2010
comment
Могу ли я сделать что-то вроде fflush(stdin);, чтобы отобразить ввод без нажатия клавиши ввода? - person Pieter; 17.03.2010
comment
@ Питер: нет. Вы должны перевести свой терминал в неканонический режим (ввод терминала обрабатывается построчно в каноническом режиме). Но это не зависит от ОС. - person Lucas; 17.03.2010

getchar() возвращает следующий символ из входного потока. Это включает, конечно, также новые строки и т. д. Тот факт, что вы не видите прогресса в своем цикле, пока не нажмете «Enter», вызван тем фактом, что ваш файловый ввод-вывод (работающий на стандартном вводе) не не передавать входной буфер в getchar(), если только он не обнаружит '\n' в конце буфера. Затем ваша подпрограмма first block обрабатывает два нажатия клавиш за один раз, завершаясь, как вы указали, появлением '\n' во входном потоке. Факт: getchar() не удалит '\n' из входного потока (зачем?).

person slartibartfast    schedule 17.03.2010

после f вы ставите «enter», что означает «/ n». так что петля заканчивается там. если вы хотите взять другой символ, просто продолжайте помещать их один за другим, как только будет нажата клавиша ввода, цикл завершится.

person Ashish Yadav    schedule 17.03.2010

Вы запрограммировали его так, что цикл завершается, когда вы читаете \n (ввод), а затем возвращаете 0; из основного, который выходит из программы.

Возможно, вы хотите что-то вроде

 while ((read = getchar()) != EOF) {
        putchar(read);
    }
person nos    schedule 17.03.2010
comment
Я пробовал это, но это создает бесконечный цикл. Я, кстати, пользователь Windows. - person Pieter; 17.03.2010
comment
Вы должны объявить переменную «чтение» как int, а не char, иначе вы вполне можете получить бесконечный цикл. Он должен выйти, если вы уничтожите его с помощью CTRL+C или завершите ввод с помощью CTRL+Z. Когда вы хотите, чтобы ваша программа закончилась? - person nos; 17.03.2010

На терминалах nx вы можете нажать Control-D, что сообщит драйверу tty вернуть входной буфер приложению, читающему его. Вот почему ^D в новой строке завершает ввод — это приводит к тому, что tty возвращает нулевые байты, что приложение интерпретирует как конец файла. Но это также работает в любом месте на линии.

person Bernd Jendrissek    schedule 18.03.2010