Чтение текстового файла из стандартного ввода останавливается на последней строке

Я написал короткую программу для проверки чтения текстовых файлов из stdin:

int main(){
    char c;

    while(!feof(stdin)){

        c = getchar();       //on last iteration, this returns '\n'

        if(!isspace(c))      //so this is false
            putchar(c);

        //remove spaces
        while (!feof(stdin) && isspace(c)){    //and this is true
                c = getchar();  //      <-- stops here after last \n
                if(!isspace(c)){
                    ungetc(c, stdin);
                    putchar('\n');
                }
        }
    }
    return 0;
}

Затем я передаю ему небольшой текстовый файл:

jimmy   8
phil    6
joey    7

с последней строкой (joey 7), заканчивающейся символом \n.

Моя проблема в том, что после того, как он прочитает и напечатает последнюю строку, а затем вернется к проверке ввода, больше не будет символов для чтения, и он просто остановится на строке, отмеченной в блоке кода.

Вопрос. Единственный способ для feof() вернуть true - это после неудачного чтения, как указано здесь: Обнаружение EOF в C< /а>. Почему последний вызов getchar не запускает EOF и как мне лучше обработать это событие?


person corporateWhore    schedule 04.09.2016    source источник
comment
Почему while ( !feof (file) ) всегда неверен?   -  person r3mainer    schedule 04.09.2016
comment
Я не уверен. Он не обнаружил никаких неудачных чтений?   -  person corporateWhore    schedule 04.09.2016
comment
Переходи по ссылке и читай. Вы должны проверить возвращаемое значение из getchar() (которое возвращает int, а не char) и протестировать его для EOF. Проверка feof() как условия оператора while() почти всегда неверна.   -  person r3mainer    schedule 04.09.2016
comment
Хорошо, но последний вызов getchar по-прежнему терпит неудачу, когда нет char для получения. Он просто висит там.   -  person corporateWhore    schedule 04.09.2016
comment
Как вы перенаправляете ввод, чтобы файл читался? На какой платформе вы находитесь?   -  person Jonathan Leffler    schedule 04.09.2016
comment
Откат. Это не сайт редактирования жизни. Получив ответ, вы не должны изменять вопрос таким образом, чтобы оставить его без контекста.   -  person too honest for this site    schedule 04.09.2016
comment
@ Олаф, понял, извиняюсь. @Jonathan Leffler, из терминала CentOS 7 со стандартным перенаправлением < text.txt   -  person corporateWhore    schedule 04.09.2016
comment
Любая книга, в которой использовалась while(!feof(fp)) глупость, должна быть сожжена. Миллионы студентов были введены в заблуждение.   -  person Weather Vane    schedule 04.09.2016


Ответы (1)


В вашем коде есть несколько проблем:

  • Вы не включили ни <stdio.h>, ни <ctype.h>, или, по крайней мере, не опубликовали весь исходный код.
  • Вы используете feof() для проверки конца файла. Это почти никогда не бывает правильным методом, как подчеркнуто в Почему «в то время как ( !feof (файл) )» всегда неправильно?
  • Вы читаете байт из потока в переменной char. Это препятствует правильному тестированию для EOF, а также приводит к неопределенному поведению для isspace(c). Измените тип на int.

Вот улучшенная версия:

#include <stdio.h>

int main(void) {
    int c;

    while ((c = getchar()) != EOF) {
        if (!isspace(c)) {
            putchar(c);
        } else {
            //remove spaces
            while ((c = getchar()) != EOF && isspace(c)) {
                continue;  // just ignore extra spaces
            }
            putchar('\n');
            if (c == EOF)
                break;
            ungetc(c, stdin);
        }
    }
    return 0;
}

Хотя ваш метод с ungetc() функционально корректен, было бы лучше использовать вспомогательную переменную таким образом:

#include <stdio.h>
#include <ctype.h>

int main(void) {
    int c, last;

    for (last = '\n'; ((c = getchar()) != EOF; last = c) {
        if (!isspace(c)) {
            putchar(c);
        } else
        if (!isspace(last))
            putchar('\n');
        }
    }
    return 0;
}
person chqrlie    schedule 04.09.2016
comment
Я прочитал ссылку и думаю, что понял тему лучше. Так что спасибо тебе. Но даже после включения предложенных вами изменений выполнение все равно останавливается на последнем вызове getchar(). В строке 11. - person corporateWhore; 04.09.2016
comment
Что вы подразумеваете под он останавливается? он должен как минимум выводить '\n' - person chqrlie; 04.09.2016
comment
Хорошо, я думаю, что это проблема отладчика eclipse. В eclipse, когда строка отладки достигает while((c = getchar()) != EOF && isspace(c), она просто останавливается и не будет продолжаться дальше. Единственный вариант, который у меня есть, это нажать кнопку остановки. Когда я скомпилировал его и запустил в терминале, все заработало нормально. Извини за это. - person corporateWhore; 04.09.2016
comment
Это определенно проблема затмения. Я только что попробовал тот же код в cLion, и он тоже работал нормально. Мне придется исследовать проблему затмения отдельно. Спасибо за помощь. - person corporateWhore; 04.09.2016