@Aliksei

При завершении работы программы падает исключение, что делать?

Здравствуйте. При завершении работы программы падает исключение.
Необработанное исключение по адресу 0x0FB2DF58 (msvcp120d.dll) в TLT1-FILE-V3.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x006E0504.


Код программы
#define _CRT_SECURE_NO_WARNINGS //Снимаем предупреждение
#include "header.h"

//list<session_student> student;
const int max_masive = 100;
session_student student[max_masive];
int student_r=0;
char buff_s[90];//буффер ввода
session_student buff_student;//буффер для обмена с листом

int main()
{
	setlocale(LC_ALL, "Russian");
	cout << "************************************" << endl;
	cout << "	Программа учета студентов	" << endl;
	cout << "************************************" << endl;
	init();
	commandlet();
	//system("exit");
	cout.clear();
	cin.clear();
	return 0;
}

void init()
{
	//student.clear();
	ifstream file("data.bin", ios::binary);
	if (file.is_open())
	{
		cout << "Чтение данных \n";
		int lt=0;
		file.read(reinterpret_cast<char*>(&student_r), sizeof(&student_r));
		for (int i = 0; i < student_r; i++)
		{
			file.read(reinterpret_cast<char*>(&buff_student), sizeof(buff_student));
			student[i] = buff_student;
		}
		file.clear();
		file.close();
	}
	else
	{
		cout << "Открыть файл не удалось";
	}
	//file.close();
}

void commandlet()
{
	bool flag = false;//Флаг
	int numbe_comand;//Номер команды
	while (flag == false)
	{
		cout << "Список базовых команд\n1) Добавление записи\n2) Редактирование записи\n3) Удаление записей по номеру группы\n4) Сформировать отчёт по задолженностям\n5) Завершить работу\n Команда: ";
		std::cin >> numbe_comand;
		switch (numbe_comand)
		{
		case 1:
			add();
			break;
		case 2:
			edit();
			break;
		case 3:
			del_group();
			break;
		case 4:
			otchet();
			break;
		case 5:
			flag = exit_program();
			break;
		case 7:
			view_db();
			break;
		default:
			break;
		}
	}
}
void otchet(void)
{
	int group;
	
	cout << "Формирование отчеьа по задолженностям: \nВведите номер группы: ";
	cin >> group;
	cout << "Фамилия | Имя | Отчество | количество-долгов\n";
	int dolg = 0;
	for (int i = 0; i < student_r; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			if (student[i].exam[j] < 25)
				dolg++;
			if (student[i].setoff[j] == 0)
				dolg++;
		}
		if (dolg != 0)
			cout << student[i].Surname.c_str() << " | " << student[i].Name.c_str() << " | " << student[i].Middle_name.c_str() << " | " << dolg << "\n";
	}
	if (dolg == 0)
		cout << "Должников в группе №" << group << " нет\n";
}

/*Добавление записи*/
void add()
{
	system("cls");
	if (student_r != max_masive)
	{
		int *group_t = new int;
		unsigned short int *exam_t = new unsigned short int[5];//Экзамены
		short int *setoff_t = new short int[5];//Зачеты
		cout << "Добавление карточки студента\nФамилия студента: ";
		cin >> buff_s;
		buff_student.Surname = string(buff_s);
		cout << "Имя: ";
		cin >> buff_s;
		buff_student.Name = string(buff_s);
		cout << "Отчество: ";
		cin >> buff_s;
		buff_student.Middle_name = string(buff_s);
		cout << "Номер группы: ";
		cin >> *group_t;
		buff_student.numbe_group = *group_t;
		delete group_t;
		cout << "Результаты экзаменов (Введите результаты по 5-ти экзаменам через пробелов):";
		cin >> exam_t[0] >> exam_t[1] >> exam_t[2] >> exam_t[3] >> exam_t[4];
		cout << "Результаты здачи 5-ти зачетов (1 - зачтено 0 - нет ввод осуществляется через пробел)";
		cin >> setoff_t[0] >> setoff_t[1] >> setoff_t[2] >> setoff_t[3] >> setoff_t[4];
		cout << "Сохранение\n";
		for (int i = 0; i < 5; i++)
		{
			buff_student.exam[i] = exam_t[i];
			buff_student.setoff[i] = setoff_t[i];
		}
		if (student_r < 100)
		{
			student[student_r] = buff_student;
			student_r++;
		}
		else
		{
			cout << "Таблица переполнена, запись не добавлена";
		}
		//student.push_back(buff_student);
		delete[] exam_t;
		delete[] setoff_t;
	}
	else
	{
		cout << "Добавить запись не удалось. переполнен массив";
	}

}

/*Редактирование записи*/
void edit()
{
	int group=0;
	char surname[30], name[30], middle_name[30];
	cout << "Редактирование записи \n Настройка фильтра 1 - по фамилии 2 -  по имени 3 - по отчеству 4 - по номеру группы\n Фильтр: ";
	cout << "Ввод поиска записи [Фамилия Имя Отчество №группы]: ";
	cin >> surname >> name >> middle_name >> group;
	cout << "id | номер группы | Фамилия | Имя | Отчество\n";
	system("cls");
	for (int i = 0; i < student_r;i++)
	{
		if (student[i].Surname == string(surname) && student[i].Name == string(name) && student[i].Middle_name == string(middle_name) && student[i].numbe_group == group)
		{
			cout << "ok \n";
			buff_student = student[i];
			buff_student = edit_note(buff_student);
			student[i] = buff_student;
		}
	}
}

session_student edit_note(session_student stud)
{
	char boolen;
	session_student stl = stud;
	cout << "Найдена следующая запись\n" << stl.numbe_group << " | ";
	cout << stl.Surname.c_str() << " | " << stl.Name.c_str() << " | " << stl.Middle_name.c_str() << " | " << "\nРедактировать следующею запись [Y/N]? ";
	cin >> boolen;
	if (boolen == 'Y' || boolen == 'y' || boolen == 'Д' || boolen == 'д')
	{
		cout << "Фамилия: ";
		cin >> buff_s;
		stl.Surname = (string)buff_s;
		cout << "Имя: ";
		cin >> buff_s;
		stl.Name = (string)buff_s;
		cout << "Отчество: ";
		cin >> buff_s;
		stl.Middle_name = (string)buff_s;
		cout << "Редактирование завершено \n";
	}
	return stl;
}

/*Выход из программы*/
bool exit_program()
{
	char key;
	printf("Выйти из программы [Y - Ввыйти с сохранением N - Ввыйти без сохранения C - Отменить завершение программы]: ");
	std::cin >> key;
	if (key == 'Y' || key == 'y')
	{
		remove("data.bin");
		ofstream file("data.bin", ios::binary);
		if (file.is_open())
		{
			file.clear();
			file.write(reinterpret_cast<char*>(&student_r), sizeof(student_r));
			for (int i = 0; i < student_r; i++)
			{
				buff_student = student[i];
				file.write(reinterpret_cast<char*>(&buff_student), sizeof(buff_student));
			}
			file.eofbit;
			file.clear();
			cout << "Закрываю потоки";
			file.close();
			//file.~basic_ofstream();
			if (!file.is_open())
				return true;
		}
		else
		{
			cout << "Открыть файл на запись не удалось.\n";
		}
	}
	if (key == 'N' || key == 'n')
	{
		return true;
	}
	return false;
}

void view_db(void)
{
	system("cls");
	cout << "№группы | Фамилия | Имя | Отчество | Экзамен №1 | Экзамен №2 | Экзамен №3 | Экзамен №4 | Экзамен №5 | Зачет №1 | Зачет №2 | Зачет №3 | Зачет №4 | Зачет №5 |\n";
	for (int i = 0; i < student_r; i++)
	{
		cout << student[i].numbe_group << " | " << student[i].Surname.c_str() << " | " << student[i].Name.c_str() << " | " << student[i].Middle_name.c_str() << " | " << student[i].exam[0] << " | " << student[i].exam[1] << " | " << student[i].exam[2] << " | " << student[i].exam[3] << " | " << student[i].exam[4] << " | " << student[i].setoff[0] << " | " << student[i].setoff[1] << " | " << student[i].setoff[2] << " | " << student[i].setoff[3] << " | " << student[i].setoff[4] << " | \n";
	}
}

void del_group(void)
{
	int group;
	system("cls");
	cout << "Какую группу вы хотите удалить? ";
	cin >> group;
	cout << "Удаление\n";
	del_reversive(group,0);
	cout << "Удаление завершено";
}

void del_reversive(int group, int lt)
{
	int chx;
	bool flag = false;
	while (!flag)
	{
		flag = true;
		for (int i = 0; i < student_r; i++)
		{
			if (student[i].numbe_group == group)
			{
				flag = false;
				chx = student_r - 1;
				if (i == chx)
				{
					student_r--;
				}
				else
				{
					chx = i + 1;
					for (int j = chx; j < student_r; j++)
						student[i] = student[j];
					student_r--;
				}
			}
		}
	}
}
Файл header.h
#include <iostream>
#include <fstream>
//#include <list>

void init(void);//Инициализация
void commandlet(void);//Список и обработка начальных команд
bool exit_program(void);//Выход из программы
void add(void);//Добавление записи
void edit(void);//Редактивание
void del_group(void);//Удаление по номеру группы
void del_reversive(int group, int lt);
void view_db(void);
void otchet(void);


using namespace std;

struct session_student
{
	int numbe_group;//Номер группы
	std::string Surname;//Фамилия
	std::string Name;//Имя
	std::string Middle_name;//Отчество
	int exam[5];//Экзамены
	int setoff[5];//Зачеты
	~session_student()
	{
		this->exam[0] = NULL;
		this->exam[1] = NULL;
		this->exam[2] = NULL;
		this->exam[2] = NULL;
		this->exam[4] = NULL;
		this->setoff[0] = NULL;
		this->setoff[1] = NULL;
		this->setoff[2] = NULL;
		this->setoff[3] = NULL;
		this->setoff[4] = NULL;
		this->Surname = "";
		this->Name = "";
		this->Middle_name = "";
		this->numbe_group = NULL;
	}
};
session_student edit_note(session_student stud);


Причем дебагер останавливается в файле xutility, в следующей строке (*_Pnext)->_Myproxy = 0;
Скажите, пожалуйста, как можно избавиться от этого исключения, а точнее от ошибки, которая скорее всего в моей программе.
  • Вопрос задан
  • 488 просмотров
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Это испорченная память, где-то ошибка в управлении памятью (например, запись за границами массива).
UPD. Ваша ошибка: в составе std::string есть внутренние неконтролируемые поля, и его нельзя побайтово сохранять в файл. Такими неконтролируемыми полями могут быть указатели, кэши-ускорители и многое другое. Вообще std::string состоит из указателя или двух, и отсюда следуют две вещи. 1) При сохранении в файл не попадут строковые данные, попадёт только указатель. К тому же в Windows нет хорошего 16-ричного просмотрщика, а без него при работе с файлами как без рук (по крайней мере начинающему, я давно обхожусь). 2) Как только вы этот указатель загрузите, std::string портится, и на деструкторе может случиться что угодно.

Вам надо самим придумать формат файла и реализовать загрузку/сохранение, используя length(), data() и front().

Важное правило: ткни в любой байт дампа вашего файла — вы должны сказать, что он значит. Из-за сложности формата это может быть сложно. Байт может быть неиспользуемым или оставленным для совместимости, но какое-то значение должно быть. Если формат многоуровневый, надо сказать назначение на всех уровнях: например, «это значение атрибута XML» на уровне XML и «это имя студента» на прикладном уровне.

Исключение: если есть объект-«чёрный ящик», который написан не нами и сериализуется гарантированно корректно, достаточно сказать: «это часть чёрного ящика». (Сериализуется — это переводится в цепочку байтов, например, файл или сетевой поток.)

Что ещё пока вижу (но это не причина ошибки).
1.
unsigned short int *exam_t = new unsigned short int[5];
Нет нужды new, невелик массив. Хватает локального массива на стеке. Аналогично остальные два new.
2. Нет нужды давать clear/close. Это фишка Си++, автоматически сработает деструктор.
3. Не называйте переменную flag, называйте wasFound (или что она реально значит).
4. sizeof(&student_r) только чудом совпадает с sizeof(student_r).
5. Не надо писать flag == false, надо !flag.
6. Функция del_reversive делает излишнюю работу и переставляет студентов, к тому же есть стандартный алгоритм remove_if.
7. while (!flag) в del_rev бессмысленно.
8. Вы же работаете со string’ами — зачем вводить информацию в буфер ограниченной длины?
9. Программа не модульная, нет нужды в хедере.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы