CodeInside
@CodeInside

Почему изменяются значения полей объекта структуры?

Программа получает логин и пароль пользователя. Функция getStudentData ищет студента в файле по указаному логину и считывает его данные. Возвращает указатель на готовый заполненный объект, если студент найден и nullptr если студент не найден. И вот в чём сутю вопроса: при первом обращении к полям структуры (через указатель) всё нормально, а при повторном - выводится какой-то мусор и "Отсутствие доступа для чтения по адресу ..." Дело в том, что между этими вызовами никакие манипуляции не происходят. В чем проблема?

Так записываю данные в "БД"
FILE * accounts_w = nullptr;
	fopen_s(&accounts_w, "Accounts.dat", "wb");
	
	char * str = "Anto_cn69";
	short size = strlen(str);
	fwrite(&size, sizeof(size), 1, accounts_w);
	fputs(str, accounts_w);

	str = "4utc1";
	size = strlen(str);
	fwrite(&size, sizeof(size), 1, accounts_w);
	fputs(str, accounts_w);

	str = "Antonyuk";
	size = strlen(str);
	fwrite(&size, sizeof(size), 1, accounts_w);
	fputs(str, accounts_w);

	str = "Arkadiy";
	size = strlen(str);
	fwrite(&size, sizeof(size), 1, accounts_w);
	fputs(str, accounts_w);

	str = "Olegovich";
	size = strlen(str);
	fwrite(&size, sizeof(size), 1, accounts_w);
	fputs(str, accounts_w);

	int age = 18;
	fwrite(&age, sizeof(age), 1, accounts_w);

	str = "ECE-1511";
	fputs(str, accounts_w);

	str = "Programming";
	size = strlen(str);
	fwrite(&size, sizeof(size), 1, accounts_w);
	fputs(str, accounts_w);

	_getch();

	fclose(accounts_w);
	delete[] str;


Student * getStudentData(FILE * accounts, char * login)
{
	Student student;
	student.login = new char[strlen(login) + 1];
	//size+1 для '\0'
	student.password = new char[MAX_PASSWORD_SIZE + 1];
	student.surname = new char[MAX_SURNAME_SIZE + 1];
	student.name = new char[MAX_NAME_SIZE + 1];
	student.patronymic = new char[MAX_PATRONYMIC_SIZE + 1];
	student.group = new char[GROUP_NAME_SIZE + 1];
	student.faculty = new char[MAX_FACULTY_SIZE + 1];

	char * temp_login = new char[MAX_LOGIN_SIZE + 1];// Получает значения логинов при считывании информации с файла
	short log_s, pass_s, surn_s, name_s, patr_s, faculty_s;//_s - "size"

	if (!CheckStructFields(student))
	{
		showMessage("Error! Not allocate memory for structure fields.");
	};

	while (std::fread(&log_s, sizeof(log_s), 1, accounts) > 0 && std::fread(temp_login, sizeof(char), log_s, accounts) > 0)
	{
		temp_login[log_s] = '\0';

		//не помню что хотел здесь написать

		if (strcmp(temp_login, login) == 0)//если введённый пользователем логин найден в "БД"
		{
			//Считывание и запись информации о студенте

			// Логин
			strcpy(student.login, login);

			// Пароль
			fread(&pass_s, sizeof(pass_s), 1, accounts);
			fread(student.password, sizeof(char), pass_s, accounts);
			student.password[pass_s] = '\0';

			// Фамилия
			fread(&surn_s, sizeof(surn_s), 1, accounts);
			fread(student.surname, sizeof(char), surn_s, accounts);
			student.surname[surn_s] = '\0';

			// Имя
			fread(&name_s, sizeof(name_s), 1, accounts);
			fread(student.name, sizeof(char), name_s, accounts);
			student.name[name_s] = '\0';

			// Отчество
			fread(&patr_s, sizeof(patr_s), 1, accounts);
			fread(student.patronymic, sizeof(char), patr_s, accounts);
			student.patronymic[patr_s] = '\0';

			// Возраст
			int age;
			fread(&age, sizeof(age), 1, accounts);
			student.age = age;

			// Группа
			fread(student.group, sizeof(char), GROUP_NAME_SIZE, accounts);
			student.group[GROUP_NAME_SIZE] = '\0';

			// Факультет
			fread(&faculty_s, sizeof(faculty_s), 1, accounts);
			fread(student.faculty, sizeof(char), faculty_s, accounts);
			student.faculty[faculty_s] = '\0';

			return &student;
		}
		else//если логины не совпадают
		{
			//"перепрыгивание" ненужной информации
			//пароль
			fread(&pass_s, sizeof(pass_s), 1, accounts);
			fseek(accounts, pass_s, SEEK_CUR);

			//фамилия
			fread(&surn_s, sizeof(surn_s), 1, accounts);
			fseek(accounts, surn_s, SEEK_CUR);

			//имя
			fread(&name_s, sizeof(name_s), 1, accounts);
			fseek(accounts, name_s, SEEK_CUR);

			//отчество
			fread(&patr_s, sizeof(patr_s), 1, accounts);
			fseek(accounts, patr_s, SEEK_CUR);

			//возраст
			int age;
			fread(&age, sizeof(age), 1, accounts);

			//группа
			fseek(accounts, GROUP_NAME_SIZE, SEEK_CUR);

			//факультет
			fread(&faculty_s, sizeof(faculty_s), 1, accounts);
			fseek(accounts, faculty_s, SEEK_CUR);
		}
	}

	//если логин не найден
	return nullptr;
}


И что в менйне:
Student * student = getStudentData(accounts, login);
		if (student == nullptr)// Если введённый логин не найден
		{
			showMessage("Entered login is not found.");
			ShowStartMenu();
			ShowLoginStr(login);
			ShowPasswordStr(strlen(password));
			goto Sign_In_Form;
		}
		else if (strcmp(password, student->password) == 0)//если пароли совпадают
		{
			//вход в систему
			//showMessage("Hello, ", student->surname, " ", student->name, ".");
			cout << student->group << endl << student->faculty << endl << student->patronymic << endl;
			cout << student->group << endl << student->faculty << endl << student->patronymic;
		}
		else//если пароль введён неверно
		{
			showMessage("Incorrect password.");
			ShowStartMenu();
			ShowLoginStr(login);
			ShowPasswordStr(strlen(password));
			goto Sign_In_Form;
		}


Повторный cout не работает. Почему?
  • Вопрос задан
  • 175 просмотров
Пригласить эксперта
Ответы на вопрос 2
@nirvimel
Из getStudentData возвращается указатель на локальный объект student.
Ответ написан
Adamos
@Adamos
Студенчеству, конечно, многое простительно, но зачем использовать С++ как С?
MAX_SURNAME_SIZE - это сколько? У моей супруги двойная фамилия (24 символа). Влезет?
MAX_PASSWORD_SIZE - сколько? Один из моих паролей - легко запоминающаяся, не подбираемая фраза на 36 символов.
А всего-то - перегнать этот "FILE * accounts" в банальный XML и читать его чем-нибудь типа pugixml.
И никаких плясок с памятью и переполнением, и никаких ограничений на длину и язык поля, и никаких простыней одинаковых операторов, в любом из которых может крыться досадная опечатка.

И никоим образом не уменьшит секьюрность, если что. Потому что ваш бинарный файл читается глазами без всяких проблем... Пароли-то - открытым текстом, небось? Хэш и соль еще не проходили?

А если этот код действительно будет использоваться, то первое, что с ним можно будет сделать - это перевести в скрипт на сервере. Нет, я не про ваш говнокод - его проще заново переписать...
Ответ написан
Ваш ответ на вопрос

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

Похожие вопросы