二进制文件读写含char*的结构体异常问题求助
解决二进制文件读写t_p_r结构体的乱码与段错误问题
你遇到的问题其实很典型——结构体里的char*成员直接写入二进制文件是踩了个常见的坑。我来给你拆解一下原因和解决方法:
问题根源
你的t_p_r结构体里的P、R1这些都是指针,它们存储的是字符串在内存中的地址,而不是字符串本身的内容。当你直接用fwrite把整个结构体写入文件时,实际上只是把这些地址数值存了进去。等你再次读取的时候,这些地址在当前进程的内存空间里要么是无效的(直接触发段错误),要么指向的是随机的内存区域(显示乱码)。
正确的写入方法:存字符串内容,不是指针
要解决这个问题,我们需要把每个字符串的长度和内容分别写入文件,这样读取时才能知道要分配多少内存来存储字符串。示例代码如下:
void saveSing(t_p_r P) { FILE* f = fopen("PR.dat", "wb"); if (!f) { // 一定要检查文件是否打开成功,别忽略这个! perror("Failed to open file for writing"); return; } // 存储P字符串:先写长度(包含终止符'\0'),再写内容 size_t len_P = strlen(P.P) + 1; fwrite(&len_P, sizeof(size_t), 1, f); fwrite(P.P, sizeof(char), len_P, f); // 用同样的方式存储R1、R2、R3 size_t len_R1 = strlen(P.R1) + 1; fwrite(&len_R1, sizeof(size_t), 1, f); fwrite(P.R1, sizeof(char), len_R1, f); size_t len_R2 = strlen(P.R2) + 1; fwrite(&len_R2, sizeof(size_t), 1, f); fwrite(P.R2, sizeof(char), len_R2, f); size_t len_R3 = strlen(P.R3) + 1; fwrite(&len_R3, sizeof(size_t), 1, f); fwrite(P.R3, sizeof(char), len_R3, f); fclose(f); }
正确的读取方法:先读长度,再分配内存存内容
读取的时候要反过来:先读取字符串的长度,然后根据长度分配足够的内存,最后把字符串内容读进去。还要注意内存分配失败的情况,避免内存泄漏:
t_p_r loadSing() { t_p_r result = {NULL, NULL, NULL, NULL}; // 初始化指针为NULL,方便后续清理 FILE* f = fopen("PR.dat", "rb"); if (!f) { perror("Failed to open file for reading"); return result; } size_t len; // 读取P字符串 if (fread(&len, sizeof(size_t), 1, f) != 1) goto cleanup; result.P = malloc(len); if (!result.P) { perror("Malloc failed for P"); goto cleanup; } fread(result.P, sizeof(char), len, f); // 读取R1 if (fread(&len, sizeof(size_t), 1, f) != 1) goto cleanup; result.R1 = malloc(len); if (!result.R1) { perror("Malloc failed for R1"); goto cleanup; } fread(result.R1, sizeof(char), len, f); // 读取R2 if (fread(&len, sizeof(size_t), 1, f) != 1) goto cleanup; result.R2 = malloc(len); if (!result.R2) { perror("Malloc failed for R2"); goto cleanup; } fread(result.R2, sizeof(char), len, f); // 读取R3 if (fread(&len, sizeof(size_t), 1, f) != 1) goto cleanup; result.R3 = malloc(len); if (!result.R3) { perror("Malloc failed for R3"); goto cleanup; } fread(result.R3, sizeof(char), len, f); fclose(f); return result; cleanup: // 如果中途出错,释放已经分配的内存 free(result.P); free(result.R1); free(result.R2); free(result.R3); fclose(f); result = (t_p_r){NULL, NULL, NULL, NULL}; return result; }
额外的注意事项
- 内存清理:使用完读取到的结构体后,一定要手动释放每个
char*成员的内存,防止内存泄漏:void freeTPR(t_p_r* ptr) { free(ptr->P); free(ptr->R1); free(ptr->R2); free(ptr->R3); // 把指针置空,避免野指针 ptr->P = ptr->R1 = ptr->R2 = ptr->R3 = NULL; } - 异常检查:所有文件操作(
fopen、fread、fwrite)都要检查返回值,避免因为文件损坏、权限不足等问题导致后续错误。 - 特殊字符串处理:如果你的字符串包含
'\0'(比如二进制数据),那不能用strlen计算长度,需要提前记录好实际的长度并存入文件。
内容的提问来源于stack exchange,提问作者pepito
相关产品推荐
相关产品推荐

