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

API对话框操作后OpenFile函数出现内存访问违规的原因

问题原因及解决方案

核心问题:直接二进制读写std::string引发内存访问违规

你遇到的0xC0000005访问违例,根源是直接对包含std::string的结构体执行二进制读写操作。std::string作为C++容器类,内部存储的是指向堆内存的指针(附带长度、容量等元数据),而非字符串的实际内容:

  • 调用fwrite写入结构体时,文件里只保存了string内部的指针值,不是字符串的真实字符。
  • 读取时fread把旧的指针值恢复到新的CCharacter_Script对象中,此时指针指向的内存要么已经被释放,要么属于无效区域。后续调用character.str.c_str()访问该内存,或者character对象析构时尝试释放这块非法内存,都会触发访问违例。

代码中的具体问题

  1. Save函数错误:直接写入整个结构体,仅持久化了std::string的内部指针,而非字符串内容。
  2. OpenFile函数错误:读取旧指针值到新std::string对象,导致该对象持有无效内存地址,后续访问或析构时崩溃。

修复方案

需要手动序列化/反序列化std::string——单独写入字符串的长度和内容,读取时先读长度再分配内存读取内容。

修复后的Save函数

void Save(int nameID, int emotationID, char script[])
{
    CCharacter_Script character;
    character.ID_Name = nameID;
    character.ID_Emotiation = emotationID;
    character.str = script;

    FILE* fp = fopen("Save_Script.bin", "rb");

    if (fp == NULL)
    {
        fp = fopen("Save_Script.bin", "wb");
    }
    else
    {
        fclose(fp);
        fp = fopen("Save_Script.bin", "ab");
    }

    // 先写入int类型成员
    fwrite(&character.ID_Name, sizeof(int), 1, fp);
    fwrite(&character.ID_Emotiation, sizeof(int), 1, fp);
    // 写入字符串长度,再写入实际内容
    size_t str_len = character.str.size();
    fwrite(&str_len, sizeof(size_t), 1, fp);
    fwrite(character.str.c_str(), sizeof(char), str_len, fp);

    fclose(fp);
}

修复后的OpenFile函数

void OpenFile()
{
    CCharacter_Script character;
    FILE* fp = fopen("Save_Script.bin", "rb");

    if (fp == NULL)
    {
        OutputDebugString("Error :: None File\n");
        return;
    }

    OutputDebugString("Reading :: Script\n");
    // 逐个读取成员,手动反序列化string
    while (true)
    {
        // 读取int成员
        int read_count = fread(&character.ID_Name, sizeof(int), 1, fp);
        if (read_count <= 0) break;
        read_count = fread(&character.ID_Emotiation, sizeof(int), 1, fp);
        if (read_count <= 0) break;

        // 读取字符串长度,再分配内存读取内容
        size_t str_len;
        read_count = fread(&str_len, sizeof(size_t), 1, fp);
        if (read_count <= 0) break;

        character.str.resize(str_len);
        read_count = fread(&character.str[0], sizeof(char), str_len, fp);
        if (read_count <= 0) break;

        myDebugMsg("Name: %d    Emotation: %d\n '%s'\n", character.ID_Name, character.ID_Emotiation, character.str.c_str());
    }
    fclose(fp);
}

额外注意事项

  • 不要对包含非POD(Plain Old Data)类型的结构体做直接二进制读写,std::string、std::vector等容器都属于非POD类型。
  • 若需要更健壮的序列化方案,可考虑JSON、XML等文本格式,或Protobuf这类专业序列化库,避免手动处理的繁琐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:24:51