K & R: Глава 6 - Почему функция getword () не читает EOF? - PullRequest
5 голосов
/ 15 декабря 2011

Это мой самый первый пост о переполнении стека, поэтому я надеюсь, что никому не наступлю.

Конечно, все входные данные приветствуются и ценятся, но те, кто наиболее подходит для ответа, действительно прочитали бы книгу, C Programming Language, 2nd ed.

Я только что закончил кодировать Упражнение 6-4, но не могу что-то выяснить. Почему функция getword () не читает EOF, пока я не нажму Ctrl + D (я кодирую на C на виртуальной машине Arch Linux)?

Многие из моих предыдущих упражнений из книги требуют чтения из stdin. Один из способов сделать это через что-то вроде

while ((c = getchar()) != EOF) {...}

В таком случае мне никогда не нужно нажимать Ctrl + D. Я ввожу данные, нажимаю Enter, буфер stdin очищается и EOF определяется автоматически. Функция getword () также опирается на getchar () в своей основе, так почему она вешает мою программу?

Функция getword () вызывается из main ():

while (getword(word, MAX_WORD) != EOF) {
    if (isalpha(word[0])) {
        root = addtree(root, word);
    }
}

Сама функция getword ():

int getword(char *word, int lim) {

    char *w = word;
    int c;

    while (isspace(c = getch())) {
    }
    if (c != EOF) {
        *w++ = c;
    }
    // This point is reached
    if (!isalpha(c)) {
        // This point is never reached before Ctrl+D
        *w = '\0';
        return c;
    }
    for ( ; --lim > 0; w++) {
        if (!isalnum(*w = getch())) {
            ungetch(*w);
            break;
        }
    }
    *w = '\0';
    return word[0];
}

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

Функции getch () и ungetch () - это те же функции, которые использовались в польском калькуляторе нотаций из главы 4 (и эта программа смогла автоматически прочитать EOF - нажав Enter):

#define BUF_SIZE 100

char buf[BUF_SIZE];
int bufp = 0;

int getch(void) {

    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) {

    if (bufp >= BUF_SIZE) {
        printf("ungetch: too many characters\n");
    }
    else {
        buf[bufp++] = c;
    }
}

Пока что это первая программа, которую я написал с начала этой книги, которая требует, чтобы я вручную вводил EOF через Ctrl + D. Я просто не могу понять, почему.

Заранее большое спасибо за объяснения ...

Ответы [ 3 ]

3 голосов
/ 15 декабря 2011

Для того, чтобы получить EOF, нужно набрать Ctrl + D - нормальное поведение для Unix-подобных систем.

Для вашего кода:

while ((c = getchar()) != EOF) {...}

нажатие Введите определенно не должен завершать цикл (если ваши настройки tty плохо испорчены).

Попробуйте скомпилировать и запустить эту программу:

#include <stdio.h>
int main( void )
{
    int c;
    while ((c = getchar()) != EOF) {
        putchar(c);
    }
    return 0;
}

Она должна напечатать всевы вводите, и оно должно завершаться только тогда, когда вы вводите control-D в начале строки (или когда вы убиваете его с помощью control-C).

2 голосов
/ 15 декабря 2011

Точка «не достигнут» будет достигнута только в том случае, если вы введете что-то вроде знака препинания во вводе или прочитаете EOF.Если вы набираете букву или пробелы, то она игнорируется.

Когда ввод поступает с терминала (стандартный ввод), EOF не обнаруживается, пока вы не наберете Control-D (или что-либо, указанное в выводе stty -a) после ввода новой строки или после нажатия другой Control-D (так, два подряд).Код читает символы новой строки, потому что символ новой строки '\n' удовлетворяет isspace().

0 голосов
/ 16 декабря 2011

Источником моего замешательства в отношении моих предыдущих программ было то, что эффект от моих предыдущих программ всегда печатался на stdout внутри цикла while, поэтому я всегда сразу видел результат, не нуждаясь кормить в EOF. Для этого дерево не печатается до тех пор, пока не закончится цикл while, поэтому столкновение с EOF было необходимо. Я не смог этого распознать, и поэтому я сходил с ума.

Еще раз спасибо за то, что выправили меня прямо!

...