fread 对空 (0kb) 文件的行为

behaviour of fread for empty (0kb) files

这是在读取空文件时给出分段错误的示例代码。

#include <stdio.h>

main()
{
    FILE *fp;
    int i = 0;
    char buffer[20];

    printf("1\n");
    fp = fopen("/home/amadhab/aa", "r+");
    printf("2\n");
    i = fread(buffer, 1, 1, fp);
    printf("3\n");
    printf("i = %d\n", i);
}

给出 o/p 作为

1
2
Segmentation fault

fread() 是否无法读取空 (0KB) 文件?

No fread 不会 对空文件失败。 Source.

正如其他人已经指出的,该错误与函数本身无关。

如果程序运行,应该会发生什么:

1
2
3
i = 0

fread()失败时,它应该 return 0(或小于请求的项目数的数字)。但是,这不会发生。这可能是因为 fp 为空。不允许将空参数传递给 fread()。可能 fp 为空,因为 /home/amadhab/aa 不存在。尝试使用它来打开文件:

#include <assert.h>

fp = fopen("/home/amadhab/aa", "r+");
assert(fp != NULL);

或者,要了解更多信息,

#include <err.h>

const char *fname = "/home/amadhab/aa";
fp = fopen(fname, "r+");
if (!fp)
    err(1, "%s", fname)

请注意,err() 函数是 BSD 扩展,但如果需要考虑可移植性,您可以在其他系统上使用 strerror()perror()

标准

来自 n1516 第 7.21.8.1 节:

The fread function reads, into the array pointed to by ptr, up to nmemb elements whose size is specified by size, from the stream pointed to by stream.

请注意 NULL 不指向流,因此通过传递 NULL 您违反了 fread() 函数的先决条件。这在第 7.1.4 节中明确说明:

If an argument to a [library] function has an invalid value (such as [...] a null pointer [...]) [...], the behavior is undefined.

在你的代码中

fp = fopen("/home/amadhab/aa", "r+");

fopen() return 值没有成功检查。如果 fopen() 失败,它将 return NULL(在 fp 中收集)和随后使用的变量 fp 用于收集 return value 将导致 undefined behaviour Note。这就是

中正在发生的事情
fread(buffer, 1, 1, fp);  // note the usage of fp here

导致分段错误。

为避免这种情况,您应该立即检查 fopen() 的 return 值,如果失败,您应该避免访问 fp.

注意:只是一个建议,学习使用调试器 [如 linux 上的 gdb] 并单步执行您的应用程序。大多数时候,它 查明确切的问题。


注意:请参阅附件 J,C99,作为未定义行为背后的原因,

An argument to a library function has an invalid value or a type not expected by a function with variable number of arguments (7.1.4).

而且,NULL 被认为是 将要传递给 fread()FILE * 的无效值。

Fread 在读取空文件时不会失败。你没有检查流打开 正确打开。

fp = fopen("/home/amadhab/aa", "r+"); 

在这种情况下,如果打开该文件失败。现在 fp 的值为 NULL。

i = fread(buffer, 1, 1, fp);

现在您正在访问 NULL 文件流。这就是分段错误的原因。为避免这种情况,您必须检查条件。

if ( ( fp = fopen("/home/amadhab/aa", "r+") ) == NULL  ){
            perror("fopen");
            exit(5);
}