zoukankan      html  css  js  c++  java
  • Bug记录 | C++对二进制文件录入、读取结构体数组遇到0xC0000005错误

    题目描述: 用I/O流类和对象的方法、C++的方法对文件进行读写操作。数据存放在结构体中,然后使用ofstream输出流对象的方法将学生成绩写入一个文本文件(自己打开它检查成功否),然后使用ifstream输入流对象的方法将数据文件的内容读取出来,最后将这些值打印显示(使用C++语句)
    分析: 题目的要求很简单, 使用IO库中给定的函数即可. 相关函数包括write read等, 可查到函数原型如下所示:


    注意, 由于ifstream(ofstream)从istream(ostream)继承而来, ifstream(ostream)实际上使用父类的readwrite函数. 对read函数, 第一个参数是读取的字符数组, 第二个是要读取的字符数. 当遇到文件结束或者在文本模式文件中遇到文件结束标记字符时读结束.
    由此, 可以写出如下的代码:

    //
    // Created by hellcat on 2020.05.27.
    //
    
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    typedef struct student {
        string name;
        int exam[4];
    }STU;
    
    int main() {
        STU stu[] = {
                { "张明明", 101, 67, 78, 82 },
                { "李天天", 102, 78, 91, 88 },
                { "王酷", 104, 56, 45, 77 },
                { "陈跑", 105, 67, 38, 47 }
        };
    
        string filename = "test.dat";
        ofstream out(filename, ios_base::binary);
        out.write(reinterpret_cast<char*>(&stu), sizeof(stu));
        out.close();
    
        ifstream in(filename, ios_base::binary);
        if(in) {
            STU __stu[4];
            in.read(reinterpret_cast<char*>(&__stu), sizeof(__stu));
            for(auto i : __stu) {
                cout<<i.name<<" ";
                for(auto j : i.exam)
                    cout<<j<<" ";
                puts("");
            }
        }
        else
            cout<<"Error: Can't open file 'test.dat'. "<<endl;
        in.close();
    }
    

    运行结果:

    虽然得到了输出, 但是返回的代码却是-1073741819 (0xC0000005), 这意味着程序并没有正常退出.
    在Google中搜索, 也没有得到返回代码的错误信息.

    1 (注: https://suying666.net/auth/register?code=yWhK 暂时有mian fei google工具)
    但Google上有很多提示可能是编译器问题, 所以先换个环境, 使用linux环境在线编译器:

    发现有大量的Error, 而

    这里的Memory Map有暗示似乎存在内存上的一些错误.

    下面进一步调试代码, 分别注释掉write和read的部分, 观察哪个部分出了问题.
    注释掉read代码时, 成功得到了期望的退出代码0:

    很显然, 问题出在read上.

    在看read的参数传入, 有一个sizeof(__stu)的存在, 而__stu中又包含有string. 但此时string大小并不确定, string中仅有两根指针. 很明显, 问题出现在string上.

    那么, 将name改为C风格字符串, 固定大小, 问题迎刃而解, 完整代码如下:

    //  
    // Created by hellcat on 2020.05.27.  
    //  
      
    #include <iostream>  
    #include <fstream>  
    using namespace std;  
      
    typedef struct student {  
        char name[10];  
        int num;  
        int exam[3];  
    }STU;  
      
    int main() {  
        STU stu[] = {  
                { "张明明", 101, 67, 78, 82 },  
                { "李天天", 102, 78, 91, 88 },  
                { "张好好", 103, 68, 82, 56},  
                { "王酷", 104, 56, 45, 77 },  
                { "陈跑", 105, 67, 38, 47 }  
        };  
      
        string filename = "test.dat";  
        ofstream out(filename, ios_base::binary);  
        out.write(reinterpret_cast<char*>(&stu), sizeof(stu));  
        out.close();  
      
        ifstream in(filename, ios_base::binary);  
        if(in) {  
            STU __stu[sizeof(stu)/sizeof(STU)];  
            in.read(reinterpret_cast<char*>(&__stu), sizeof(__stu));  
            cout<<"姓名"<<" 学号"<<" 语文"<<" 数学"<<" 英语"<<endl;  
            for(auto i : __stu) {  
                cout<<i.name<<" "<<i.num<<" ";  
                for(auto j : i.exam)  
                    cout<<j<<" ";  
                puts("");  
            }  
        }  
        else  
            cout<<"Error: Can't open file 'test.dat'. "<<endl;  
        in.close();  
    }  
    
    


    最后, 经过2小时的探索Bug成功解决!
    求解过程中也请教了我的C++老师, 在此表示感谢!!

  • 相关阅读:
    Java8 lambda表达式语法 1
    Spring WebMVC 4.1返回json时 406(Not Acceptable)
    上传 第三方jar包 nexus
    Nexus 使用配置
    Nexus 安装 使用说明
    mysql 常用命令
    JedisPoolConfig配置
    tomcat 管理端 安全措施
    Java ReentrantLock和synchronized两种锁定机制的对比
    spring 在web容器启动时执行初始化方法
  • 原文地址:https://www.cnblogs.com/tedukuri/p/12972929.html
Copyright © 2011-2022 走看看