Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/3: Рейтинг темы: голосов - 3, средняя оценка - 5.00
Даценд
Модератор
Эксперт .NET
4808 / 4266 / 2787
Регистрация: 20.04.2015
Сообщений: 7,725
1

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

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

Пытаюсь разобраться со структурами в бинарных файлах.
Допустим, есть массив структур. Записываю его в бинарный файл (закомментированный код). Всё прекрасно записывается.
Затем читаю и добавляю структуры в вектор. Всё прекрасно читается, добавляется и даже выводится на экран.
Но при выполнении строки 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
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.12.2017, 22:48
Ответы с готовыми решениями:

"Нарушение прав доступа при чтении по адресу" при организации класса очереди типа FIFO
Есть класс очереди типа FIFO: class FIFO { private: int* queue; int cols; public:...

Ошибка при работе с OpenCV: "нарушение прав доступа при чтении по адресу"
Привет, всем:-) Имеется следующий код: #include &lt;opencv2/core/core.hpp&gt; #include...

"Нарушение прав доступа при чтении по адресу 0x00000000"
код: #define _CRT_SECURE_NO_WARNINGS #include &lt;stdio.h&gt; #include &lt;math.h&gt; int strtoint(char *s)...

Ошибка "нарушение прав доступа при чтении по адресу."
Использовать стек для решения следующей задачи. В текстовом файле записана без ошибок формула...

Необработанное исключение в "0x00412b4a" в "kursovik.exe": 0xC0000005: Нарушение прав доступа при чтении "0x00000004".
Программа компилируется нормально но потом на строчке MoveToEx(hdc,Mas.a]-&gt;x*20,Mas.a]-&gt;y*20,0);...

8
alex white
272 / 224 / 91
Регистрация: 27.06.2016
Сообщений: 635
Завершенные тесты: 1
13.12.2017, 23:11 2
Даценд, вы записываете и читаете бинарные данные "как есть". Учитывая, что std::string содержит в себе указатель на данные в динамической памяти (разве что малые строки могут быть размещены внутри самого объекта), вы считываете из файла висячий указатель, а не саму строку.
1
Manowar
Отава Ё.
2016 / 561 / 186
Регистрация: 12.03.2016
Сообщений: 2,135
Завершенные тесты: 1
13.12.2017, 23:28 3
Запись класса в bin файл
1
Даценд
Модератор
Эксперт .NET
4808 / 4266 / 2787
Регистрация: 20.04.2015
Сообщений: 7,725
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
14.12.2017, 00:57
Kuzia domovenok
2767 / 2398 / 616
Регистрация: 25.03.2012
Сообщений: 8,576
Записей в блоге: 1
Завершенные тесты: 1
14.12.2017, 01:18 5
size_t nameLength; нужно бы сделать локальной переменной, а не полем класса
Ещё char* cname = new char[nameLength]; в конце этой же функции освободить delete cname

а так вроде норм
1
Даценд
Модератор
Эксперт .NET
4808 / 4266 / 2787
Регистрация: 20.04.2015
Сообщений: 7,725
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
QuakerRUS
542 / 477 / 226
Регистрация: 30.10.2017
Сообщений: 1,503
Завершенные тесты: 4
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
4808 / 4266 / 2787
Регистрация: 20.04.2015
Сообщений: 7,725
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
QuakerRUS
542 / 477 / 226
Регистрация: 30.10.2017
Сообщений: 1,503
Завершенные тесты: 4
14.12.2017, 11:52 9
Даценд, а если у вас неожиданно файл оборвется после чтения id, или в этот момент произойдет отказ диска? В программу попадут некорректные данные, что может вызвать ошибку. То, что вы и наблюдаете, когда делаете проверку на eof перед чтением первого блока. eof устанавливается после попытки считать несуществующий элемент, а не когда указатель находится в конце файла. eof-проверку вы успешно проходите перед чтением несуществующего элемента, и далее программа ведет себя некорректно, пытаясь обработать данные, полученные из нерабочего потока.
1
14.12.2017, 11:52
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.12.2017, 11:52

Необработанное исключение в "0x00414558" в "467.exe": 0xC0000005: Нарушение прав доступа при чтении "0xabababbb"
При выполнении этого кода #include &lt;iostream&gt; #include&lt;conio.h&gt; using namespace std; int...

Необработанное исключение в "0x778e15de" в "dir-3.exe": 0xC0000005: Нарушение прав доступа при чтении "0x00000000"
#include &lt;windows.h&gt; #include &lt;d3d9.h&gt; LRESULT __stdcall WndProc(HWND hWnd, UINT msg, WPARAM...

Необработанное исключение в "0x775e15de" в "laba3.exe": 0xC0000005: Нарушение прав доступа при чтении "0xfdfdfdf9".
вылезает ошибка Необработанное исключение в &quot;0x775e15de&quot; в &quot;laba3.exe&quot;: 0xC0000005: Нарушение прав...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru