Home > OS >  C Exception "Access violation reading location"
C Exception "Access violation reading location"

Time:11-21

#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;
}

Hello, I'm trying to make a program which writes several "reviews" to a binary file, then reads a certain registry. The program seems to work, but, in the end, it always throws an exception: "Exception thrown at 0x00007FF628E58C95 in trabalho.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF." How can I solve this? Thank you!

CodePudding user response:

The operator sizeof (review) does not return the length of containing strings. This is due to the fact that string class contain pointers to real strings, which are located in a separated location of the memory, allocated dynamically. You should use explicitly the length of strings, and write explicitly the strings instead of the class. Same thing with reading from file. Read strings first, then attribute to review.

CodePudding user response:

The problem is that you can't read/write std::string objects they way you are. std::string holds a pointer to variable-length character data that is stored elsewhere in memory. Your code is not accounting for that fact.

To be able to seek to a specific object in a file of objects the way you are attempting, you have to use fixed-sized objects, eg:

#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;
}

Otherwise, to deal with variable-length data, you need to (de)serialize each object instead, eg:

#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;
}
  •  Tags:  
  • c
  • Related