【问题标题】:C++ Exception "Access violation reading location"C++ 异常“访问冲突读取位置”
【发布时间】:2021-11-20 14:16:23
【问题描述】:
#include <iostream>    
#include <fstream>     
using namespace std;

struct review {
    string text;
    string date;
};

void getRegistry(int i) {
    review* reg = new review;
    ifstream file;
    file.open("test.txt", ios::binary);
    if (file) {
        file.seekg(i * sizeof(review), ios::beg);
        file.read(reinterpret_cast<char*>(reg), sizeof(review));
        cout << reg->text;
        file.close();
    }
    delete reg;
}

void generateBinary()
{
    ofstream arq("test.txt", ios::binary);
    review x;
    x.text = "asdasdasd";
    x.date = "qweqweqwe";
    for (int i = 1; i <= 1000000; i++)
    {
        arq.write(reinterpret_cast<const char*>(&x), sizeof(review));
    }

    arq.close();
}


int main() {

    generateBinary();
    getRegistry(2);
    
    return 0;
}

您好,我正在尝试编写一个程序,它将多个“评论”写入二进制文件,然后读取某个注册表。该程序似乎可以工作,但最后它总是抛出异常:“在 trabalho.exe 中在 0x00007FF628E58C95 抛出异常:0xC0000005:访问冲突读取位置 0xFFFFFFFFFFFFFFFF。”我该如何解决这个问题?谢谢!

【问题讨论】:

  • 简单:您可以在调试器中运行它。
  • 但问题是您序列化了一个 std::string (我假设;您不包含该标头并且您使用命名空间 std,因此您不告诉我们那是哪个字符串)一个字节一个字节地写出来。您是否知道字符串包含一个成员,该成员是指向特定于正在运行的程序的某个地址的指针?字节图像序列化一开始是个坏主意,因为它取决于编译器选项和系统。但作为第一次尝试,它可以使用固定长度的字符数组而不是字符串。
  • 要获得更好(特别是更便携)的选项,请考虑使用序列化库,请参阅here
  • 程序似乎可以工作”是什么意思?您的意思是它以您期望的格式(并且您可以再次阅读)正确地将一百万条“评论”写入文件 test.txt?请尽可能清楚地描述实际和期望的行为。

标签: c++


【解决方案1】:

问题是您无法按照您的方式读取/写入std::string 对象。 std::string 持有一个指向存储在内存中其他地方的可变长度字符数据的指针。您的代码没有考虑到这一事实。

为了能够以您尝试的方式寻找对象文件中的特定对象,您必须使用固定大小的对象,例如:

#include <iostream>    
#include <fstream> 
#include <cstring>    
using namespace std;

struct review {
    char text[12];
    char date[12];
};

void getRegistry(int i) {
    ifstream file("test.txt", ios::binary);
    if (file) {
        if (!file.seekg(i * sizeof(review), ios::beg)) throw ...;
        review reg;
        if (!file.read(reinterpret_cast<char*>(&reg), sizeof(reg))) throw ...;
        cout << reg.text;
    }
}

void generateBinary()
{
    ofstream arq("test.txt", ios::binary);
    review x = {};
    strncpy(x.text, "asdasdasd", sizeof(x.text)-1);
    strncpy(x.date, "qweqweqwe", sizeof(x.date)-1);
    for (int i = 1; i <= 1000000; ++i) {
        if (!arq.write(reinterpret_cast<char*>(&x), sizeof(x))) throw ...;
    }
}

int main() {
    generateBinary();
    getRegistry(2);
    return 0;
}

否则,要处理变长数据,就需要(de)serialize代替每个对象,例如:

#include <iostream>    
#include <fstream> 
#include <cstdint>    
using namespace std;

struct review {
    string text;
    string date;
};

string readStr(istream &is) {
    string s;
    uint32_t len;
    if (!is.read(reinterpret_cast<char*>(&len), sizeof(len))) throw ...;
    if (len > 0) {
        s.resize(len);
        if (!is.read(s.data(), len)) throw ...;
    }
    return s;
}

void skipStr(istream &is) {
    uint32_t len;
    if (!is.read(reinterpret_cast<char*>(&len), sizeof(len))) throw ...;
    if (len > 0) {
        if (!is.ignore(len)) throw ...;
    }
}

void writeStr(ostream &os, const string &s) {
    uint32_t len = s.size();
    if (!os.write(reinterpret_cast<char*>(&len), sizeof(len)) throw ...;
    if (!os.write(s.c_str(), len)) throw ...;
}

review readReview(istream &is) {
    review r;
    r.text = readStr(is);
    r.date = readStr(is);
    return r;
}

void skipReview(istream &is) {
    skipStr(is);
    skipStr(is);
}

void writeReview(ostream &os, const review &r) {
    writeStr(is, r.text);
    writeStr(is, r.date);
}

void getRegistry(int i) {
    ifstream file("test.txt", ios::binary);
    if (file) {
        while (i--) skipReview(file);
        review reg = readReview(file);
        cout << reg.text;
    }
}

void generateBinary()
{
    ofstream arq("test.txt", ios::binary);
    review x;
    x.text = "asdasdasd";
    x.date = "qweqweqwe";
    for (int i = 1; i <= 1000000; ++i) {
        writeReview(arq, x);
    }
}

int main() {
    generateBinary();
    getRegistry(2);
    return 0;
}

【讨论】:

    【解决方案2】:

    运算符sizeof (review) 不返回包含字符串的长度。这是因为字符串类包含指向真实字符串的指针,这些字符串位于内存的单独位置,动态分配。您应该显式使用字符串的长度,并显式编写字符串而不是类。从文件中读取也是如此。先读取字符串,然后属性进行审查。

    【讨论】:

    • 对不起,我不太明白你让我做什么。你能给我举个例子吗?谢谢!
    猜你喜欢
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2015-05-01
    • 2013-11-22
    • 1970-01-01
    • 2014-10-26
    相关资源
    最近更新 更多