存储在二进制文件中的int不成功fread(),分段错误
似乎有10个问题的顺序和(大多数)成功的答案解决因C中误用的fread()导致的分段错误。尽管如此,我遇到了这样的问题,但还没有找到解决方案。
我有一个二进制文件,包含一个int
(称为nbins )和一个float
数组(大小为nbins )。 当我尝试读取此文件时,它会成功打开并指向文件句柄,但在读取nbins int
时会出现分段错误错误。 这是一个最小的例子:
#include #include #include #define BPATH "/path/to/file" int main(int agrc, char **argv) { FILE *fd; int num; char fname[500]={}; int nbins; float *coords; num = 5; sprintf(fname,"%s/file%d.dat", BPATH, num); if(!(fd=fopen(fname,"rb"))) { printf("Can't open file: %s\n\n",fname); exit(0); } printf("Reading input file:\n"); printf("%p: %s\n", fd, fname); // prints successfully fread(&nbins, sizeof(int), 1, fd); printf("nbins = %d", nbins); // seg faults before this print /* EDIT: the above print isn't properly flushed without an \n * The seg fault was not caused by the fread(), but the lack of * the above print lead to the confusion */ coords = malloc(nbins * sizeof(float)); fread(coords, sizeof(float), nbins, fd); fclose(fd); free(coords); return(0); }
该文件是使用以下格式创建的:
int nbins[1]; nbins[0] = 5; // this 5 is just an example... fwrite(nbins, sizeof(int), 1, file_ptr); fwrite(coords, sizeof(float), nbins[0], file_ptr);
我也尝试过使用:
int *nbins = malloc(sizeof(int)); fread(nbins, sizeof(int), 1, fd);
但这并没有解决问题。 该文件确实存在且可读; 我可以使用Python读取它,使用NumPy的fromfile()
。 我错过了一些明显的东西吗 谢谢!
您可能有未定义的行为 ,具有以下方案:
-
int nbins;
不初始化nbins
,因此它包含垃圾数据,可能是一个非常大的数字。 -
fread(&nbins, sizeof(int), 1, fd);
没有经过测试,所以可能会失败,并保持nbins
未初始化。 阅读有关恐惧的内容 。 -
printf("nbins = %d", nbins);
没有\n
并且没有显式的fflush
所以不要显示任何东西(因为stdout
通常是行缓冲的)。 -
coords = malloc(nbins * sizeof(float));
会请求大量内存,因此会失败并在coords
获取NULL
-
fread(coords, sizeof(float), nbins, fd);
写入NULL
指针,因为UB而导致分段违规
你很幸运。 情况可能更糟 (我们都可能被黑洞消灭)。 你也可以尝试一些鼻子恶魔 ,或者更糟糕的是,有一些似乎显然有效的执行。
下次, 请避免UB 。 我不想在黑洞中消失,所以请耐心等待。
顺便说一下,如果您使用GCC ,请编译所有警告和调试信息: gcc -Wall -Wextra -g
。 它会警告你。 如果没有,你将获得gdb
调试器下的SEGV。 在Linux上, valgrind和strace也可以提供帮助。
请注意,无用的初始化(例如, 显式的 int nbins = 0;
在您的情况下)在实践中不会造成伤害。 优化编译器可能会删除它们,如果它们没用(当它们没用时,就像你的情况一样,它们非常快)。
强制阅读
Lattner的博客: 每个C程序员应该了解UB
另请阅读您正在使用的每个function的文档(甚至与printf
一样常见)。