I wrote a program that reads information about students (first name, last name and points for three verification tests). Works, in principle. But when you exit the console when the program ends, the error takes off:

An exception was thrown: read access violation. _Pnext was 0x114999C .

What does it mean? Below is the code of the program in which the place of the error is highlighted by comments.

 #include "stdafx.h" #include <fstream> #include<iostream> #include <iomanip> #include <string> using namespace std; int main() { fstream stud; fstream bin_stud; stud.open("stud.txt", ios::in); bin_stud.open("a.dat", ios::app | ios:: binary); int col = 0; //подсчет количества студентов string name1; string surname1; int test11; int test12; int test13; while (!stud.eof()) { stud >> name1; stud >> surname1; stud >> test11; stud >> test12; stud >> test13; bin_stud.write((char *)&name1, sizeof(name1)); bin_stud.write((char *)&surname1, sizeof(surname1)); bin_stud.write((char *)&test11, sizeof(test11)); bin_stud.write((char *)&test12, sizeof(test12)); bin_stud.write((char *)&test13, sizeof(test13)); col++; } bin_stud.close(); stud.close(); bin_stud.open("a.dat", ios::in | ios:: binary); for (int i = 0; i < col; i++) //вот здесь я хочу вывести содержимое бинарного файла в консоль, все выводится, но после работы программы вылетает ошибка. Если же вывод убрать из кода, то все работает нормально { bin_stud.read((char *)&name1, sizeof(name1)); bin_stud.read((char *)&surname1, sizeof(surname1)); bin_stud.read((char *)&test11, sizeof(test11)); bin_stud.read((char *)&test12, sizeof(test12)); bin_stud.read((char *)&test13, sizeof(test13)); cout << name1 << " "; cout << surname1 << " "; cout << test11 << " "; cout << test12 << " "; cout << test13<< " "; cout << endl; } bin_stud.close(); system("pause"); return 0; } 

    1 answer 1

    To begin with, this is a loop condition when reading records from a file.

     while (!stud.eof()) 

    incorrect. For example, if the last record of a file is read.

      stud >> name1; stud >> surname1; stud >> test11; stud >> test12; stud >> test13; 

    the end-of-file condition has not yet come. Therefore, the loop will proceed to the next iteration, when there is no record in the record file. Therefore, all these variables, in which the values ​​from the file in the previous iteration were entered, will be reused to write them to the output file.

    Therefore, it would be better to write

     while ( stud >> name1 && stud >> surname1 && stud >> test11 && stud >> test12 && stud >> test13 ) { //... } 

    Better yet, read line by line and then split this string into separate fields using the standard function std::getline and the string input stream std::istringstream .

    Next in these sentences

      bin_stud.write((char *)&name1, sizeof(name1)); bin_stud.write((char *)&surname1, sizeof(surname1)); 

    you are trying to write the objects themselves of type std::string , and not those strings that they store. Therefore, these sentences do not make sense.

    You should write the lines that are stored in these objects, not the objects themselves. This raises the question of the alignment of fields, since the lines in the general case can have different lengths. One approach is to keep its length before each line, and then the line itself.

    For example,

     std::string::size_type n; n = name1.size(); bin_stud.write((char *)&n, sizeof(n)); bin_stud.write( name1.c_str(), n); n = surname1.size(); bin_stud.write((char *)&n, sizeof(n)); bin_stud.write( surname1.c_str(), n); 

    And then, accordingly, read the lines in accordance with this format, that is, first read the length of the string, and then the string itself and put it into an object of type std::string .

    This is how a value written by an object of type std :: string to a file can look, and then read it from

     #include <iostream> #include <fstream> #include <string> #include <memory> int main() { { std::string s("IWProgrammer"); std::ofstream bin_stud("a.dat", std::ios::binary); std::string::size_type n = s.size(); bin_stud.write(reinterpret_cast<char *>(&n), sizeof(n)); bin_stud.write(s.c_str(), n); } { std::string s; std::ifstream bin_stud("a.dat", std::ios::binary); std::string::size_type n; bin_stud.read(reinterpret_cast<char *>(&n), sizeof(n)); std::cout << "n = " << n << std::endl; std::unique_ptr<char[]> buffer(new char[n]); bin_stud.read(buffer.get(), n); s.assign( buffer.get(), buffer.get() + n ); std::cout << s << std::endl; } } 

    Output of the program to the console

     n = 12 IWProgrammer 
    • but then why does everything work for me and even write to a binary file? Yes, and everything is read correctly too, and the error crashes after closing the console? - IWProgrammer
    • and if you change the condition of the cycle - it will not read everything - IWProgrammer
    • @IWProgrammer Your program has undefined behavior. You simply write and read objects of class std :: string in one program while they have not yet been deleted. And if you break your program into two programs, the first of which will write data to the file, and the second read, then the second program will immediately fall out with an error. - Vlad from Moscow
    • @IWProgrammer Why will not all be read? - Vlad from Moscow
    • no, everything deduces, sorry. I do not quite understand what is wrong with the withdrawal. After all, it reads everything correctly, and displays it correctly on the console. That is, there is no error anywhere, but when you press any key to exit the console, the error appears - IWProgrammer