如何将包含动态分配数组的结构体写入二进制文件?
你踩了C语言动态结构体序列化的经典坑!
这段代码的问题很明确:结构体里的dynamicArray是个指针,它存的只是内存里的地址,不是数组里的实际元素。当你用fwrite直接把整个结构体丢进文件时,只会把id和这个地址值写进去——64位系统下int占4字节,指针占8字节,加上结构体对齐补到16字节,所以文件大小刚好是16字节,完全没把那100个int元素写入。更糟的是,就算之后你把这个结构体读回来,那个指针地址在新的进程里根本无效,根本访问不到原来的数组内容。
正确的做法:分两步写入数据
要把带动态数组的结构体完整存进文件,得拆成几个步骤来:
- 先写结构体里的固定数据(比如
id),再写入数组的长度(这很关键,不然读的时候不知道要分配多大内存),最后把数组的实际元素写进去。 - 读取的时候反过来:先读固定数据,再读数组长度,分配对应大小的内存,最后把元素读到新分配的数组里。
下面是修改后的完整代码,包含写入和读取的示例:
写入文件的完整代码
#include <stdio.h> #include <stdlib.h> struct SomeStruct{ int id; int* dynamicArray; int arrayLength; // 新增字段:记录数组长度,方便后续读取 }; int main(){ struct SomeStruct test; test.id = 5; test.arrayLength = 100; // 明确数组的元素个数 // 给动态数组分配内存 test.dynamicArray = malloc(sizeof(int)*test.arrayLength); if (!test.dynamicArray) { perror("Failed to allocate memory for array"); return 1; } // 给数组赋值(做测试用,实际场景根据需求填充) for(int i=0; i<test.arrayLength; i++){ test.dynamicArray[i] = i; } // 打开文件准备写入 FILE* handle = fopen("data", "wb"); if(!handle){ perror("Failed to open file for writing"); free(test.dynamicArray); return 1; } // 1. 写入固定字段:id和数组长度 fwrite(&test.id, sizeof(test.id), 1, handle); fwrite(&test.arrayLength, sizeof(test.arrayLength), 1, handle); // 2. 写入动态数组的实际元素 fwrite(test.dynamicArray, sizeof(int), test.arrayLength, handle); // 收尾工作:关闭文件+释放内存 fclose(handle); free(test.dynamicArray); return 0; }
读取文件的完整代码(供你验证用)
#include <stdio.h> #include <stdlib.h> struct SomeStruct{ int id; int* dynamicArray; int arrayLength; }; int main(){ struct SomeStruct test; // 打开文件准备读取 FILE* handle = fopen("data", "rb"); if(!handle){ perror("Failed to open file for reading"); return 1; } // 1. 读取固定字段:id和数组长度 fread(&test.id, sizeof(test.id), 1, handle); fread(&test.arrayLength, sizeof(test.arrayLength), 1, handle); // 2. 根据读取到的长度分配内存 test.dynamicArray = malloc(sizeof(int)*test.arrayLength); if (!test.dynamicArray) { perror("Failed to allocate memory for array"); fclose(handle); return 1; } // 3. 读取动态数组的元素 fread(test.dynamicArray, sizeof(int), test.arrayLength, handle); // 验证读取结果(可选) printf("Read id: %d\n", test.id); printf("First 5 elements of array: "); for(int i=0; i<5; i++){ printf("%d ", test.dynamicArray[i]); } printf("\n"); // 收尾工作 fclose(handle); free(test.dynamicArray); return 0; }
几个关键注意点
- 绝对不要直接写入指针:指针只是内存地址,换个进程甚至同一进程重启后这个地址就没用了,必须写入指针指向的实际数据。
- 一定要记录数组长度:写入时存下数组长度,读取时才能准确分配内存,不然根本不知道要读多少元素。
- 内存管理不能忘:动态分配的内存不管是写入还是读取后,都要记得用
free释放,避免内存泄漏。 - 加上错误检查:文件打开、内存分配都可能失败,加上
perror的错误提示,调试起来会方便很多。
内容的提问来源于stack exchange,提问作者Amirabbas asadi
相关产品推荐
相关产品推荐

