2016-09-26 6 views
2

Такие вопросы могут показаться одним из тех придирчивых соображений, но я скорее прошу вас дать подробное объяснение того, что происходит, чтобы удовлетворить мое любопытство.Неопределенное поведение консольного приложения при использовании scanf и имитируемого EOF

Давайте предположим, что мы имеем следующий фрагмент кода:

#include <stdio.h> 

int main(void) 
{ 
    char ch; 

    scanf("%c", &ch); 
    printf("%d\n", ch); 

    return 0; 
} 

После компиляции, можно ввести в начале строки моделируемых EOF с CTRL + Z ярлыка и нажмите ENTER - это делается в два раза.

Выход выглядит следующим образом:
^ Z
^ Z
-52
Нажмите любую клавишу для продолжения. , ,

1) Что происходит прямо сейчас?

У меня есть еще одно сомнение по поводу такого цикла:

while (scanf("%c", &ch) != EOF) 
    printf("%c\n", ch); 

printf("BYE!\n"); 

выход будет:
^ Z
^ Z
BYE!
Нажмите любую клавишу, чтобы продолжить. , ,

2) Почему это не прекращается после первого моделирования EOF?

EDIT: Я искал еще ответы на SO, касающиеся мои сомнения, и я думаю, что это трудно использовать scanf(), так как он получил лучшие заменители, как fgets() или fread(). Пожалуйста, обратите внимание на другой пример ниже:

int input; 
char ch; 

while (scanf("%d", &input) != 1) //checking for bad input 
    while ((ch = getchar()) != '\n') //disposing of bad input 
     putchar(ch); 

printf("BYE!\n"); 

вход I в пять раз CTRL + Z в начале линии и выход стал бы:
^ Z
^ Z
^ Z
^ Z
^ Z
^ Z
^ Z
^ Z
^ Z
^ Z
^ CPНажмите любую клавишу для продолжения. , ,
Я добавил еще пять EOF и должен был убить программу с помощью CTRL + C на последней строке.

3) Почему пространство появилось на 5-й линии и было видно до конца (иногда два пробела перед «^ CPНажмите любую клавишу, чтобы продолжить ...»)?

Последний пример поправку петли сверху (нет смысла в коде):

while (scanf("%d", &input) != EOF); 

printf("BYE!\n"); 

Выход:
^ Z
^ Z
^ Z
BYE!
Нажмите любую клавишу, чтобы продолжить. , ,

4) Почему мы используем три раза CTRL + Z вместо двух, как написано выше комментарий?

+3

(1) Когда вы указываете EOF с Control-Z, ничего не назначается 'ch' так что вы получите неопределенную (полу-случайное) значение напечатан для 'ch'. (2) В Unix, если вы указали EOF (обычно с Control-D) в качестве первого символа ввода, вам не нужно будет его повторять; если вы набрали символ, произнесите пробел, а затем введите Control-D, который отправляет пустую строку в программу, но программы продолжают ждать новой строки - или другого EOF. Если вы находитесь в Windows (правдоподобно, поскольку вы используете Control-Z вместо Control-D), правила могут немного отличаться; вам может потребоваться дважды указать EOF. –

+1

Шаг 1: Не используйте 'ch', когда' scanf ("% c", & ch)! = 1', как в 'scanf ("% c ", &ch); printf ("% d \ n ", ch);' – chux

+0

@JonathanLeffler Спасибо! Я использую Windows прямо сейчас, и он может использовать двойную эмуляцию EOF. Что, если буфер (предположим, что мы используем буферизацию строк) имеет следующие символы: abc'EOF '\ n? Почему он печатает графическое представление управляющий символ и перемещение каретки на одну позицию вправо вместо того, чтобы заканчивать один символ раньше? – MrDonMatti

ответ

0

Ваш код вызывает неопределенное поведение. Если scanf() не может прочитать байт для строки формата "%c", он возвращает EOF и оставляет ch неинициализированным.

Лучше писать код так:

while (scanf("%c", &ch) == 1) 
    printf("%c\n", ch); 

printf("BYE!\n");