C语言fseek()函数使用异常:读取指定结构体结果不符问题排查
问题排查:fread读取指定结构体位置错误
核心原因:写入逻辑的多余偏移操作
你的代码中,每次调用fwrite写入结构体后,额外执行了fseek(fp, sizeof(tools), SEEK_CUR),这会让文件指针在写完一个结构体后再跳过一个结构体的长度。最终文件的存储结构变成:
结构体1 → 空白块(大小等于单个结构体)→ 结构体2 → 空白块 → ... → 结构体100 → 空白块
相当于每个有效结构体之间都间隔了一个空结构体的位置,导致文件实际占用了200个结构体的空间。
当你试图通过fseek(fp, sizeof(tools)*50, SEEK_SET)定位第51个结构体时,实际指向的是第26个有效结构体的位置(前50个偏移单位里,每2个单位对应1个有效结构体:50/2=25,第25+1=26个),这就是你读取到26的原因。
另外纠正一个误解:fwrite执行后会自动移动文件指针,指向写入内容的下一个位置,完全不需要额外调用fseek。
修正后的代码
#include <stdio.h> #include <stdlib.h> typedef struct tools { int recordno; char toolname[50]; int quantity; float cost; } tools; void recordprinter(tools a) { printf("%d %s %d %f\n", a.recordno, a.toolname, a.quantity, a.cost); } int main() { FILE * fp; // 用wb+创建并读写二进制文件,避免旧文件残留数据干扰 fp = fopen("file.txt", "wb+"); if (fp == NULL) { // 增加文件打开失败的判断 perror("Failed to open file"); return 1; } tools * a = (tools *)malloc(100 * sizeof(tools)); if (a == NULL) { // 增加内存分配失败的判断 perror("Failed to allocate memory"); fclose(fp); return 1; } // 初始化结构体数组 for (int i = 0; i < 100; i++) { a[i].cost = 0; a[i].toolname[0] = 'a'; a[i].toolname[1] = '\0'; a[i].quantity = 0; a[i].recordno = i + 1; } // 修正写入逻辑:去掉多余的fseek,fwrite自动移动指针 for (int i = 0; i < 100; i++) { fwrite(a + i, sizeof(tools), 1, fp); } // 重置文件指针到开头 fseek(fp, 0, SEEK_SET); // 定位到第51个结构体的起始位置(前50个结构体的总长度) fseek(fp, sizeof(tools) * 50, SEEK_SET); // 读取到a[3] fread(a + 3, sizeof(tools), 1, fp); recordprinter(a[3]); // 现在会输出51 // 释放资源 free(a); fclose(fp); return 0; }
额外优化点
- 增加了文件打开和内存分配的错误判断,避免程序崩溃
- 改用
wb+模式打开文件,确保每次运行都是全新的文件内容,避免旧数据干扰 - 写入循环也可以简化为一次
fwrite写入整个数组,效率更高:
fwrite(a, sizeof(tools), 100, fp);
内容的提问来源于stack exchange,提问作者Veerain
相关产品推荐
相关产品推荐

