You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二进制文件读写含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;
}

额外的注意事项

  1. 内存清理:使用完读取到的结构体后,一定要手动释放每个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;
    }
    
  2. 异常检查:所有文件操作(fopen、fread、fwrite)都要检查返回值,避免因为文件损坏、权限不足等问题导致后续错误。
  3. 特殊字符串处理:如果你的字符串包含'\0'(比如二进制数据),那不能用strlen计算长度,需要提前记录好实际的长度并存入文件。

内容的提问来源于stack exchange,提问作者pepito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:47:54