C++调用oku()函数后出现Access Reading Error问题求助
解决你的C++二进制文件读取后内存访问错误问题
嘿,我一眼就看出问题出在哪了——你直接对包含std::string的结构体做二进制读写,这绝对是C++新手常踩的坑,也是导致你程序结束时触发Access Reading Error的根本原因。
为什么会崩溃?
std::string不是简单的字符数组,它内部是个带指针的容器:实际的字符串内容存在堆内存里,string对象本身只存了指向这块内存的指针、字符串长度这些元数据。当你用file2.read((char *)&kisi[i], sizeof(kisi[i]))直接把二进制数据读进结构体时:
- 你读进来的是之前写入的旧指针地址,不是实际的字符串内容
- 程序结束时,
kisi数组里的所有string对象会自动调用析构函数,尝试释放这些旧指针指向的内存——但这些内存要么早就被释放了,要么根本不属于当前进程,自然就触发了内存访问错误(就是你看到的_Pnext相关报错)
另外,你的oku()函数里还有个小bug:循环内部又定义了int i = 0;,这会让循环永远只处理kisi[0],不过这不是崩溃的直接原因,但也得修。
怎么修复?
要正确读写带string的结构体,不能直接读写整个结构体,必须逐个成员处理,尤其是string类型的成员,得单独读写长度和内容:
1. 修复你的oku()函数
void oku() { cout << "okuma islemi yapiliyor"; ifstream file2("kisi.txt", ios::in | ios::binary); // 一定要检查文件是否打开成功,不然白忙活 if (!file2.is_open()) { cerr << "Dosya acilamadi!" << endl; return; } for (int i = 0; i < 20; i++) { cout << "suanda cursor " << file2.tellg() << endl; // 先读写基本数据类型的成员 file2.read((char *)&kisi[i].id, sizeof(kisi[i].id)); file2.read((char *)&kisi[i].cinsiyet, sizeof(kisi[i].cinsiyet)); file2.read((char *)&kisi[i].depozito, sizeof(kisi[i].depozito)); file2.read((char *)&kisi[i].oda_no, sizeof(kisi[i].oda_no)); // 读写数组类型的成员 file2.read((char *)kisi[i].odenmis_k, sizeof(kisi[i].odenmis_k)); file2.read((char *)kisi[i].endeks, sizeof(kisi[i].endeks)); file2.read((char *)kisi[i].fatura, sizeof(kisi[i].fatura)); // 重点处理std::string成员:先读长度,再读内容 size_t str_len; // 处理TC字段 file2.read((char *)&str_len, sizeof(str_len)); kisi[i].TC.resize(str_len); file2.read(&kisi[i].TC[0], str_len); // 处理Ad字段 file2.read((char *)&str_len, sizeof(str_len)); kisi[i].Ad.resize(str_len); file2.read(&kisi[i].Ad[0], str_len); // 剩下的string字段(Soyad、dogumgunu、tel等)都按这个逻辑处理 file2.read((char *)&str_len, sizeof(str_len)); kisi[i].Soyad.resize(str_len); file2.read(&kisi[i].Soyad[0], str_len); file2.read((char *)&str_len, sizeof(str_len)); kisi[i].dogumgunu.resize(str_len); file2.read(&kisi[i].dogumgunu[0], str_len); file2.read((char *)&str_len, sizeof(str_len)); kisi[i].tel.resize(str_len); file2.read(&kisi[i].tel[0], str_len); file2.read((char *)&str_len, sizeof(str_len)); kisi[i].eposta.resize(str_len); file2.read(&kisi[i].eposta[0], str_len); file2.read((char *)&str_len, sizeof(str_len)); kisi[i].girist.resize(str_len); file2.read(&kisi[i].girist[0], str_len); file2.read((char *)&str_len, sizeof(str_len)); kisi[i].cıkıst.resize(str_len); file2.read(&kisi[i].cıkıst[0], str_len); } file2.close(); cout << "Islem tamamlandi"; getchar(); }
2. 对应的写入函数也要同步修改
如果你之前是用write((char *)&kisi[i], sizeof(kisi[i]))写入文件的,那必须改成和读取对应的方式,逐个成员写入,比如:
void yaz() { ofstream file("kisi.txt", ios::out | ios::binary); if (!file.is_open()) { cerr << "Dosya acilamadi!" << endl; return; } for (int i = 0; i < 20; i++) { // 写入基本类型成员 file.write((char *)&kisi[i].id, sizeof(kisi[i].id)); file.write((char *)&kisi[i].cinsiyet, sizeof(kisi[i].cinsiyet)); file.write((char *)&kisi[i].depozito, sizeof(kisi[i].depozito)); file.write((char *)&kisi[i].oda_no, sizeof(kisi[i].oda_no)); // 写入数组 file.write((char *)kisi[i].odenmis_k, sizeof(kisi[i].odenmis_k)); file.write((char *)kisi[i].endeks, sizeof(kisi[i].endeks)); file.write((char *)kisi[i].fatura, sizeof(kisi[i].fatura)); // 写入string成员:先写长度,再写内容 size_t str_len = kisi[i].TC.size(); file.write((char *)&str_len, sizeof(str_len)); file.write(kisi[i].TC.c_str(), str_len); str_len = kisi[i].Ad.size(); file.write((char *)&str_len, sizeof(str_len)); file.write(kisi[i].Ad.c_str(), str_len); // 剩下的string字段也按这个逻辑写进去 } file.close(); }
3. 额外要注意的点
- 每次操作文件都要检查是否打开成功,避免后续操作触发未定义行为
- 把
oku()循环里的int i = 0;删掉,不然循环变量被覆盖,逻辑全错 - 如果以后修改了结构体的成员,读写函数也要同步更新,不然会出现数据错位的问题
内容的提问来源于stack exchange,提问作者Hakan Bakacak
相关产品推荐
相关产品推荐

