C编程:EOF作为一个字符

5

当在命令控制台编写C程序时,如果有一个函数尝试使用SCANF询问用户输入CHAR变量,并且用户键入CTRL+Z(EOF)并按回车键,会发生什么?

例如:

char promptChar()
{
    char c;
    printf("Enter a character: ");
    scanf("%c", &c);
    return c;
}

如果用户键入CTRL+Z并按回车键,promptChar()会返回什么?因为如果我理解EOF,它是一个int。
3个回答

11

首先:

scanf()不是语言本身定义的。
char不是语言本身定义的。

好了,说完这个...

scanf()函数返回一个整数。该整数是赋值给输入项的数量或宏EOF的值,如果在第一个转换之前发生输入失败,则为EOF的值。
你没有检查scanf()调用的返回值,所以你不知道发生了什么。一切可能都运行良好,或者输入流可能会在第一个转换之前结束,或者(不适用于%c)可能会出现转换失败。

测试scanf()的返回值。确实,始终测试所有<stdio.h>函数的返回值

char ch;
int result = scanf("%c", &ch);
if (result == 1) /* all ok */;
else if (result == 0) /* conversion failure: value of `ch` is indeterminate */;
else if (result == EOF) /* input failure; value of `ch` is indeterminate */;

scanf()调用的结果为EOF时,如果你想获得更多有关输入失败原因的信息,可以使用feof()和/或ferror()

else if (result == EOF) {
    if (feof(stdin)) {
        /* no data in input stream */
    }
    if (ferror(stdin)) {
        /* error if input stream (media ejected? bad sector? ...?)
    }
}
回答你的问题:promptChar()会返回什么? 它将返回char类型的不确定值。
您可以模仿处理字符的库函数的例子,并从promptChar()返回int。 这将是读取的字符值转换为unsigned char或负int(EOF)以表示错误情况。 例如,阅读fgetc()的描述。

此外,在这个例子中,返回值将是不确定的,因为他正在返回一个本地变量。 - Patrice Bernassola
2
@Patrice:不完全是,返回的是c的值而不是c本身或其地址。当你返回指向局部变量的指针时,会出现问题。 - pmg
1
“始终测试所有< stdio.h >函数的返回值” - 我不同意。你会每次调用printf时都检查返回值和errno吗?对我来说,这是过度的。如果像这样的简单输出失败,你将无法做任何有用的事情。 - mk12

4

来自Linux scanf(3)手册页:

“如果在第一个成功的转换或匹配失败发生之前到达输入结尾,则返回值EOF。如果发生读取错误,则也会返回EOF,此时流的错误指示器(请参见ferror(3))被设置,并且errno被设置为指示错误。”

请注意,这段内容涉及scanf的返回值,而不是结果参数。


-1

这取决于您使用的命令行 shell,但您真的不应该设计任何程序来期望从交互提示符中读取控制字符。

大多数命令行 shell 将拦截一些控制字符并使用它们告诉 shell 做事情。例如,ctrl-s 和 ctrl-q 经常启动和停止 shell 的输出字符显示。在某些 shell 上,ctrl-z 实际上将被视为关闭 shell 的命令。


EOF不是控制字符。它根本不是来自数据流中的某个字节--它是一个值,位于有效字符范围之外(按照惯例,在大多数平台上它是0xffffffff),在底层系统调用报告文件结束时返回。 - Andy Ross
@Andy:当文件的read()返回零字节数据时,就会发生EOF。当您在终端上键入Control-D(或Control-Z)时,它会将任何待处理字符发送到从终端读取的程序。如果没有待处理字符,则read()返回0,这被解释为EOF。而EOF在几乎所有平台上都是-1;在64位平台上不是0xFFFFFFFF。 - Jonathan Leffler
乔纳森:我知道。我觉得你非常同意我的看法。EOF不是“控制字符”。它根本不是流的一部分。而且我说“大多数”平台,所以我不明白为什么要挑剔。我用十六进制写它是为了表明它不是一个字符。 - Andy Ross
1
是的,ASCII 定义了 EOT(传输结束,04)ETX(文本结束,03),甚至 EM(介质结束),但没有 EOF。不过有一个 FS(文件分隔符)。 - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接