C функция scanf (), как завершить EOF / EOT? - PullRequest
2 голосов
/ 25 марта 2020

Я написал простую программу для проверки функции scanf () в C. Он в основном читает с терминала: char на char, , перепечатывание , return value и чтение char; и завершить, если EOF / EOT встречаются или если \n newline читается.

#include <stdio.h>
#include <stdbool.h>

int main(void) {
    char c; int ret;

    printf("Enter the chars to test: ");

    //LOOP (scan & print) only when return is not EOF and char is not newline
    while ( ((ret = scanf("%c", &c)) != EOF) && c!='\n' ) {
        printf("%i %c\n", ret, c);
    }
    return 0;
}

Правильно завершается при нажатии новой строки (Enter). Но это не будет заканчиваться одним Ctrl-D. Один Ctrl-D будет вызывать грипп sh напечатанных символов и печатать их. Затем после этого он снова будет ждать ввода, хотя EOF было отправлено с Ctrl-D. Если мы нажмем Ctrl-D снова во второй раз сразу после 1-го (2х) или просто Enter, он прекратится. Таким образом, вам понадобится два последовательных Ctrl-D для завершения программы (или l oop в этом случае).

Пример:

Если вы введете 987 на терминале, затем нажмите Enter; тогда 1 9, 1 8, 1 7 будут печататься на новой строке каждый.

Если вы введете 987 на терминале, затем нажмите Ctrl-D; тогда 1 9 будут напечатаны в той же строке (потому что после ввода 987 не будет напечатано Enter), 1 8 , 1 7 будет напечатано на новой строке. Затем он все еще будет ожидать дополнительных вводов, если только он не будет завершен путем непосредственного ввода 2-го числа подряд Ctrl-D или с новой строки (Enter). Так что он (программа) остановится (выйдет из l oop) только после newline или 2-го числа подряд Ctrl-D.

Я запутался. Не должен ли один Ctrl-D посланный остановить l oop здесь? Что я должен сделать, чтобы остановить программу (scanf l oop) после получения только одного Ctrl-D?

Я протестировал код на Lubuntu 19.10 с g cc 9.2.1.

Ответы [ 2 ]

2 голосов
/ 25 марта 2020

Проблема в scanf() не возвращает EOF до тех пор, пока не прекратится ожидание ввода и не встретится EOF. (ваш "%c" спецификатор преобразования в противном случае примет любой символ, включая символ '\n', как действительный и считает его успешным преобразованием)

При вводе строки символов, например "abcdefg" и попытка нажать Ctrl + d (с указанием конца ввода), ввод ("abcdefg") обрабатывается, и когда достигается 'g', тогда scanf() блокирует ожидание на вашем следующий вход. (потому что произошло успешное преобразование и не произошло совпадения или сбоя ввода)

Один раз Ctrl + d вводится второй раз (с указанием конца ввода), когда нет ввода для обработки, EOF достигается перед первым успешным преобразованием, и происходит ошибка ввода , scanf() затем возвращает EOF.

См .: man 3 scanf - ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ сечение и C11 Standard - 7.21.6.2 Функция fscanf (p16)

0 голосов
/ 25 марта 2020

Проверьте возвращаемое значение для одного, а не EOF. Когда eof достигается в первый раз, возвращается ноль. При следующем сканировании после нуля возвращается EOF.

while ( ((ret = scanf("%c", &c)) == 1) && c!='\n' ) {
    printf("%i %c\n", ret, c);
}

Это поведение указано для стандартной библиотеки C.

В случае успеха функция возвращает количество элементов списка аргументов успешно заполнен. Это число может соответствовать ожидаемому количеству элементов или быть меньше (даже ноль) из-за сбоя сопоставления, ошибки чтения или достижения конца файла .

Если произойдет ошибка чтения или будет достигнут конец файла во время чтения, будет установлен соответствующий индикатор (feof или ferror).

Вы можете добавить if (feof(stdin) != 0) break; в тело l oop, если используете более сложный формат ввода.

Если вы читаете только символы, не лучше ли использовать fgetc

...