13

在查看fgets§7.21.7.2, 3 的 ISO C11 标准时,返回值是关于概要代码的:

#include <stdio.h>
char *fgets(char* restrict s, int n, FILE* restrict stream);

如果成功,fgets函数将返回s 。如果遇到文件结尾并且没有字符被读入数组,则数组的内容保持不变并返回一个空指针。如果在操作过程中发生读取错误,则数组内容是不确定的,并返回一个空指针。

该标准说,对于文件结尾返回空指针并且没有读入任何字符或发生读取错误。我的问题是,仅仅从fgets和返回的空指针,有没有办法区分这两种情况中的哪一种导致了错误?

4

2 回答 2

9

如果失败是由文件结束条件引起的,则另外设置 eof 指示符(请参阅 feof())。在这种情况下,str 指向的数组的内容不会改变。如果失败是由其他错误引起的,则在流中设置错误指示器(请参阅 ferror())。str 指向的数组的内容是不确定的(它甚至可能不是以空值结尾的)。

因此,您需要检查feof()ferror()确定错误。

这个网站

于 2017-07-23T04:47:53.147 回答
9

有没有办法区分这两种情况中的哪一种导致了错误?

是的,用feof()ferror()来区分。@没事没事


然而,正确使用很重要。考虑两个代码:

char buf[100];
fgets(s, sizeof s, stream);
if (feof(stream)) return "End-of-file occurred";
if (ferror(stream)) return "Input error occurred"; 


if (fgets(s, sizeof s, stream) == NULL) {
  if (feof(stream)) return "End-of-file occurred";
  if (ferror(stream)) return "Input error occurred"; 
  return "Should never get here";
}

第二个NULL根据 OP 的建议正确测试返回值。

第一个可能会遇到一个罕见的问题。测试ferror(stream)一个标志。此标志可能已由先前的I/O 函数调用设置,stream因此这fgets()不一定是错误的原因。最好检查结果,fgets()看看这个函数是否失败。

如果代码在检测到错误后继续使用stream,请务必在继续之前清除错误 - 就像尝试重试一样。

if (ferror(stream)) {   
  clearerr(stream);
  return "Input error occurred");
}

请注意,这会clearerr()清除错误和文件结束标志。

这同样适用于,但大多数代码都是在文件结尾为真时feof()使用退出的。stream


有第三种病态接收方式NULL,既不feof()也不ferror()返回NULL,如fgets() 返回 NULL 且符合短缓冲区?. 仔细阅读 C 规范有 3 个“如果”,其中没有一个可能是正确的,因此缺少规范 - 这意味着 UB。

于 2017-07-23T11:16:17.617 回答