Эксперт .NET
5875 / 4752 / 2940
Регистрация: 20.04.2015
Сообщений: 8,361
1

"Нарушение прав доступа при чтении по адресу" при чтении структур из бинарного файла

13.12.2017, 22:48. Показов 4435. Ответов 8
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Пытаюсь разобраться со структурами в бинарных файлах.
Допустим, есть массив структур. Записываю его в бинарный файл (закомментированный код). Всё прекрасно записывается.
Затем читаю и добавляю структуры в вектор. Всё прекрасно читается, добавляется и даже выводится на экран.
Но при выполнении строки return 0; получаю ошибку "Нарушение прав доступа при чтении по адресу".
Код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
 
struct student
{
    int id;
    string name;
    int age;
};
 
int main()
{
        //student group[3];
    //group[0].id = 1; group[0].name = "Ivanov I.I.";  group[0].age = 25;
    //group[1].id = 2; group[1].name = "Petrov P.P.";  group[1].age = 35;
    //group[2].id = 3; group[2].name = "Sidorov S.S.";  group[2].age = 20;
    //ofstream out_file("e://file.dat", ios::binary | ios::out);
    //for (int i = 0; i < 3; i++)
    //{
    //  out_file.write((char*)(group+i), sizeof(student));
    //}
    //out_file.close();
 
    vector<student> group;
    student tmp;
    ifstream in_file("e://file.dat", ios::binary | ios::in);
    while (in_file.read((char*)(&tmp), sizeof(student))) //читаем
        group.push_back(tmp); //добавляем
    in_file.close();
    for (auto stud : group)
        cout << stud.id << "\t" << stud.name << "\t" << stud.age << endl; //выводим
    return 0; //а здесь нарушение прав доступа при чтении по адресу...
}
Если выделить память под tmp динамически, а после чтения присвоить nullptr, то ошибки нет:
C++
1
2
3
4
5
6
7
8
9
10
vector<student> group;
student *tmp = new student;
ifstream in_file("e://file.dat", ios::binary | ios::in);
while (in_file.read((char*)(tmp), sizeof(student))) 
    group.push_back(*tmp);
tmp = nullptr;
in_file.close();
for (auto stud : group)
    cout << stud.id << "\t" << stud.name << "\t" << stud.age << endl;
delete tmp;
Собственно вопросы: почему всё так происходит и как сделать правильно?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.12.2017, 22:48
Ответы с готовыми решениями:

нарушение прав доступа при чтении по адресу
Здравстуйте. Хочу передать кучу параметров в функцию Font font; POINT screen; VertexArray...

Нарушение прав доступа при чтении по адресу
Помохите! При работе со строками выдает вот такую ошибку. При проверке с английским алфавитом все...

Нарушение прав доступа при чтении по адресу
Доброго времени суток форумчане, не понимаю откуда берется ошибка #define...

Нарушение прав доступа при чтении по адресу
Здравствуйте, форумчане. Дабы не писать долго я описал свою проблему в видео...

8
277 / 226 / 93
Регистрация: 27.06.2016
Сообщений: 639
13.12.2017, 23:11 2
Даценд, вы записываете и читаете бинарные данные "как есть". Учитывая, что std::string содержит в себе указатель на данные в динамической памяти (разве что малые строки могут быть размещены внутри самого объекта), вы считываете из файла висячий указатель, а не саму строку.
1
1718 / 567 / 187
Регистрация: 12.03.2016
Сообщений: 2,169
13.12.2017, 23:28 3
Запись класса в bin файл
1
Эксперт .NET
5875 / 4752 / 2940
Регистрация: 20.04.2015
Сообщений: 8,361
14.12.2017, 00:57  [ТС] 4
Попробовал читать/писать поля раздельно.
Вот что получилось:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
 
struct student
{
    public:
        int id;
        string name;
        int age;
 
        void write(ofstream &file)
        {
            file.write((char*)&id, sizeof(id));
            nameLength = name.size();
            file.write((char*)&nameLength, sizeof(nameLength));
            file.write(name.c_str(), nameLength);
            file.write((char*)&age, sizeof(age));
        }
 
        bool read(ifstream &file)
        {
            if(!file.read((char*)&id, sizeof(id))) return false;
            file.read((char*)&nameLength, sizeof(nameLength));
            char* cname = new char[nameLength];
            file.read(cname, nameLength);
            name = string(cname, nameLength);
            file.read((char*)&age, sizeof(age));
            return true;
        }
    private:
        size_t nameLength;
};
 
int main()
 
{
    student group[3];
    group[0].id = 1; group[0].name = "qwertyuiopqwertyuiop a.d.";  group[0].age = 25;
    group[1].id = 2; group[1].name = "adfvjanfdpvajdfpvadjfnvodf g.g.";  group[1].age = 35;
    group[2].id = 3; group[2].name = "aouhdfbvosdfhvbaodfhvbdfovhsdbfvodhfvb h.h.";  group[2].age = 20;
    ofstream out_file("e://file.dat", ios::binary | ios::out);
    for (int i = 0; i < 3; i++)
    {
        group[i].write(out_file);
    }
    out_file.close();
 
    vector<student> groupvec;
    student tmp;
    ifstream in_file("e://file.dat", ios::binary | ios::in);
    while (tmp.read(in_file)) 
        groupvec.push_back(tmp);
    in_file.close();
    for (auto stud : groupvec)
        cout << stud.id << "\t" << stud.name << "\t" << stud.age << endl;
    return 0;
}
Если это страшный г-код, то так и скажите. Только объясните, почему
Особо интересно мнение о методах в структуре, и использовании private-поля для хранения длины поля name.
0
4066 / 3319 / 925
Регистрация: 25.03.2012
Сообщений: 12,496
Записей в блоге: 1
14.12.2017, 01:18 5
size_t nameLength; нужно бы сделать локальной переменной, а не полем класса
Ещё char* cname = new char[nameLength]; в конце этой же функции освободить delete cname

а так вроде норм
1
Эксперт .NET
5875 / 4752 / 2940
Регистрация: 20.04.2015
Сообщений: 8,361
14.12.2017, 01:28  [ТС] 6
Kuzia domovenok,
Благодарю.
Вечно забываю память освобождать и с локальным nameLength совершенно согласен.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void write(ofstream &file)
{
    file.write((char*)&id, sizeof(id));
    size_t nameLength = name.size();
    file.write((char*)&nameLength, sizeof(nameLength));
    file.write(name.c_str(), nameLength);
    file.write((char*)&age, sizeof(age));
}
 
bool read(ifstream &file)
{
    if(!file.read((char*)&id, sizeof(id))) return false; //вот эта проверка
    size_t nameLength;
    file.read((char*)&nameLength, sizeof(nameLength));
    char* cname = new char[nameLength];
    file.read(cname, nameLength);
    name = string(cname, nameLength);
    file.read((char*)&age, sizeof(age));
    delete[] cname;
    return true;
}
А ссылку на поток в функцию передавать это нормально?
И проверка чтения корректна?
0
1467 / 1008 / 456
Регистрация: 30.10.2017
Сообщений: 2,800
14.12.2017, 02:26 7
Цитата Сообщение от Даценд Посмотреть сообщение
А ссылку на поток в функцию передавать это нормально?
Да.

Цитата Сообщение от Даценд Посмотреть сообщение
И проверка чтения корректна?
В данном случае проверяется только корректность чтения первого значения. Думаю правильнее будет считать все значения и после этого проверить поток на ошибки. Перед созданием динамического массива проверка думаю тоже не помешает.

Добавлено через 5 минут
Так же, если б у вас текстовые поля имели фиксированный размер, можно было бы сделать например так.

C++
1
2
3
4
5
// ...
file.write((char *)&MyStruct, sizeof(MyStruct));
// ...
file.read((char *)&MyStruct, sizeof(MyStruct));
// ...
1
Эксперт .NET
5875 / 4752 / 2940
Регистрация: 20.04.2015
Сообщений: 8,361
14.12.2017, 10:45  [ТС] 8
Цитата Сообщение от QuakerRUS Посмотреть сообщение
В данном случае проверяется только корректность чтения первого значения.
Это задумывалось как проверка на то, есть ли еще что читать в потоке.
Пробовал проверять через eof, выбрасывает исключение:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
bool read(ifstream &file)
{
    if(file.eof()) return false;
    file.read((char*)&id, sizeof(id));
    size_t nameLength;
    file.read((char*)&nameLength, sizeof(nameLength));
    char* cname = new char[nameLength];
    file.read(cname, nameLength);
    name = string(cname, nameLength);
    file.read((char*)&age, sizeof(age));
    delete[] cname;
    return true;
}
0
1467 / 1008 / 456
Регистрация: 30.10.2017
Сообщений: 2,800
14.12.2017, 11:52 9
Даценд, а если у вас неожиданно файл оборвется после чтения id, или в этот момент произойдет отказ диска? В программу попадут некорректные данные, что может вызвать ошибку. То, что вы и наблюдаете, когда делаете проверку на eof перед чтением первого блока. eof устанавливается после попытки считать несуществующий элемент, а не когда указатель находится в конце файла. eof-проверку вы успешно проходите перед чтением несуществующего элемента, и далее программа ведет себя некорректно, пытаясь обработать данные, полученные из нерабочего потока.
1
14.12.2017, 11:52
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.12.2017, 11:52
Помогаю со студенческими работами здесь

Нарушение прав доступа при чтении по адресу
Доброго времени суток. Делал задание из Лафоре, и заметил, что при попытке прочитать данные из...

Нарушение прав доступа при чтении по адресу
Есть функция, которая сортирует структуру AEROFLOT по методу Шелла. Там я считаю количество...

Нарушение прав доступа при чтении по адресу
В приведённом ниже коде возникает ошибка времени выполнения с текстом из названия. Проблема в том,...

Нарушение прав доступа при чтении по адресу
#include &lt;iostream&gt; #include &lt;locale.h&gt; #include &lt;cstring&gt; #include &lt;cmath&gt; using namespace...

Нарушение прав доступа при чтении по адресу
Выдаёт ошибку на 61 строчке кода, главное выводит pB, а pB не хочет #include &lt;stdio.h&gt;...

Нарушение прав доступа при чтении по адресу
Доброго времени суток! Пишу некую прогу. Так вот у меня выпадает ошибка, на скринах показана....

Нарушение прав доступа при чтении по адресу
Ошибка &quot;Вызвано исключение по адресу 0x515EF6BC (ucrtbased.dll) в l2_2.exe: 0xC0000005: нарушение...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru