使用scanf和模拟EOF时控制台应用程序的未定义行为

时间:2016-09-26 19:38:56

标签: c scanf eof

这类问题可能看起来像是一个令人讨厌的问题,但我宁愿请你详细解释为了满足我的好奇心。

我们假设我们有以下代码:

#include <stdio.h>

int main(void)
{
    char ch;

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

    return 0;
}

编译完成后,可以使用CTRL + Z快捷键在行模拟EOF的开头键入,然后按ENTER键 - 这样做两次。

输出如下:
    ^ Z
    ^ Z
    -52
     按任意键继续 。 。

1)现在发生了什么?

我对这种循环有另一个疑问:

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

printf("BYE!\n");

输出将是:
^ Z
^ Z
BYE!
按任意键继续 。 。 。

2)为什么在第一次EOF模拟后它不会终止?

编辑:我搜索了有关我的疑问的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");

我在行的开头输入了五次 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 而不是两次,因为它是在上面的评论中写的?

1 个答案:

答案 0 :(得分:0)

您的代码调用未定义的行为。如果scanf()无法读取格式字符串"%c"的字节,则会返回EOF并使ch保持未初始化状态。

最好以这种方式编写代码:

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

printf("BYE!\n");