C语言读取含结构体数组的结构体二进制文件遇段错误问题
问题根源
你遇到的段错误是因为Movie结构体里的View *Views是指针类型——当你把Movie结构体写入二进制文件时,保存的只是这个指针在内存中的地址值,而不是它指向的View数组实际数据。读取时,这个地址在当前进程的内存空间里是无效的(要么未分配,要么属于其他内存区域),直接访问movie.Views[i]自然会触发段错误。
修复方案
要正确读取这类包含动态数组的结构体,需要分两步读取:先读取Movie的非指针部分,再根据CountView的值动态分配内存,最后读取对应数量的View数据。
修复后的读取代码
#include <stdlib.h> #include <stdio.h> #include <string.h> // 假设MAX_LINE_SIZE是已定义的常量,这里示例定义为256 #define MAX_LINE_SIZE 256 typedef struct view { long CustomerID; int Rating; char Date[11]; } View; typedef struct movie { long MovieID; long YearOfRelease; char Title[MAX_LINE_SIZE]; long CountView; View *Views; // 动态数组指针,读取时需单独分配内存 } Movie; void readDataFromBinary() { FILE *f = fopen("../saved_data/save_data.bin", "rb"); if (f == NULL) { perror("fopen"); exit(EXIT_FAILURE); } Movie movie; // 先读取Movie的固定长度非指针成员,以MovieID作为读取循环的判断依据 while (fread(&movie.MovieID, sizeof(long), 1, f) == 1) { // 依次读取其他非指针成员 fread(&movie.YearOfRelease, sizeof(long), 1, f); fread(movie.Title, sizeof(char), MAX_LINE_SIZE, f); fread(&movie.CountView, sizeof(long), 1, f); // 根据CountView分配对应大小的内存 movie.Views = malloc(movie.CountView * sizeof(View)); if (movie.Views == NULL) { perror("malloc"); fclose(f); exit(EXIT_FAILURE); } // 一次性读取所有View数组数据 fread(movie.Views, sizeof(View), movie.CountView, f); // 打印读取到的数据 printf("MovieId : %ld\n", movie.MovieID); printf("YearOfRelease : %ld\n", movie.YearOfRelease); printf("Title : %s", movie.Title); printf("CountView : %ld\n\n", movie.CountView); for (int i = 0; i < movie.CountView; i++) { printf("%ld\n", movie.Views[i].CustomerID); printf("%d\n", movie.Views[i].Rating); printf("%s\n", movie.Views[i].Date); } // 释放动态分配的内存,避免内存泄漏 free(movie.Views); movie.Views = NULL; } if (fclose(f) == -1) { perror("fclose"); exit(EXIT_FAILURE); } }
关键注意事项
- 对应的写入代码必须同步修改:不能直接用
fwrite(&movie, sizeof(Movie), 1, f)写入整个结构体,而是要分两部分写入——先写Movie的非指针成员,再写Views指向的数组数据。示例写入逻辑如下:
void writeDataToBinary(Movie *movies, int movieCount) { FILE *f = fopen("../saved_data/save_data.bin", "wb"); if (f == NULL) { perror("fopen"); exit(EXIT_FAILURE); } for (int i = 0; i < movieCount; i++) { Movie *m = &movies[i]; // 写入非指针成员 fwrite(&m->MovieID, sizeof(long), 1, f); fwrite(&m->YearOfRelease, sizeof(long), 1, f); fwrite(m->Title, sizeof(char), MAX_LINE_SIZE, f); fwrite(&m->CountView, sizeof(long), 1, f); // 写入View数组的实际数据 fwrite(m->Views, sizeof(View), m->CountView, f); } fclose(f); }
- 如果你的二进制文件是用
fwrite(&movie, sizeof(Movie), 1, f)直接写入的,那这个文件只保存了指针地址,没有实际的View数据,这种情况下无法恢复数据,必须重新用正确的写入逻辑生成新的二进制文件。
内容的提问来源于stack exchange,提问作者Valentin Blanc
相关产品推荐
相关产品推荐

