记住:fgetc()
返回int
,而不是char
。它必须返回一个int
,因为它的一组返回值包含所有可能的有效字符和一个单独的(负)EOF指示符。
有两种可能的陷阱,如果你使用类型为char
的c
代替int
:
如果类型char
与您签订的编译器,你会发现一个有效的字符为EOF。通常,在ISO 8859-1(又名拉丁语1代码集)中,字符ÿ(y-umlaut,在Unicode中被正式称为LATIN LOWER CASE Y WITH DIAERESIS,U + 00FF,十六进制代码0xFF)将被检测为等同于EOF,这是一个有效的角色。
如果类型char
是无符号的,那么比较永远不会是真的。
这两个问题是严重的,无一不是通过使用正确的类型回避:
FILE *fp = fopen("file.txt", "r");
if (fp != 0)
{
int c;
int nl = 0;
while ((c = fgetc(fp)) != EOF)
if (c == '\n')
nl++;
printf("Number of lines: %d\n", nl);
}
注意该类型是FILE
而不是File
。请注意,在尝试通过fp
阅读之前,您应该检查文件是否已打开。
如果我明确给予CTRL + d,当我使用char c
即使检测到EOF。
这意味着您的编译器为您提供了char
作为签名类型。这也意味着您将无法在包含ÿ的文件中准确地计算行数。
与CP/M和DOS不同,Unix不使用任何字符来表示EOF;当没有更多字符可读时,您到达EOF。令许多人感到困惑的是,如果您在终端键入某个组合键,程序会检测到EOF。实际发生的事情是,终端驱动程序识别该字符并将任何未读字符发送到该程序。如果没有未读字符,程序会返回0字节,这与您到达文件结尾时的结果相同。因此,字符组合(通常,但并非总是,Ctrl-D)似乎将'EOF'发送给程序。但是,如果您使用的是cat >file
,则不会将该字符存储在文件中;此外,如果您读取包含control-D的文件,则该文件是字符值为0x04的完美字符。如果一个程序生成一个control-D并将它发送给一个程序,那么这并不表示程序的EOF。它完全是Unix终端的一种属性(tty和pty - teletype和pseudo-teletype - devices)。
[fgetc无法识别EOF]的可能重复(http://stackoverflow.com/questions/3977223/fgetc-does-not-identify-eof),另请参阅http://stackoverflow.com/questions/11057259/fgetc-checking-eof以及其他很多 – Mat
另请注意:EOF不是“存储在文件中”,它只是I/O函数告诉你它们到达文件结尾的一种方式。末尾没有存储魔术字节。 – Mat
请注意它应该是'FILE * fp;'而不是'File * fp;',并且您还应该在通过变量'fp'读取任何内容之前检查文件是否已成功打开。 –