Что значит исключение _Pnext было 0x114999C.?

366
16 января 2017, 20:41

Написал программу, которая считывает информацию о студентах (имя фамилию и баллы за три проверочных теста). Работает, в принципе. Но когда выходишь из консоли по завершении работы программы, то вылетает ошибка:

Вызвано исключение: нарушение доступа для чтения. _Pnext было 0x114999C.

Что это значит? Ниже привожу код программы, в котором место ошибки выделено комментариями.

#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;
}
Answer 1

Начнем с того, что это условие цикла при чтении записей из файла

while (!stud.eof())

некорректное. Например, если будет прочитана последняя запись файла

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

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

Поэтому лучше было бы записать

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

А еще лучше считывать построчно, а затем эту строку разбивать на отдельные поля, используя стандартную функцию std::getline и строковый входной поток std::istringstream.

Далее в этих предложениях

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

вы пытаетесь записать сами объекты типа std::string, а не те строки, которые они хранят. Поэтому эти предложения не имеют смысла.

Вам следует записывать строки, которые хранятся в этих объектах, а не сами объекты. При этом возникает вопрос о выравниваемости полей, так как строки в общем случае могут иметь разную длину. Один из подходов состоит в том, чтобы перед каждой строкой сохранять ее длину, а затем саму строку.

Например,

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);

А затем, соответственно, считывать строки в соответствии с этим форматом, то есть сначала считывать длину строки, а затем саму строку и заносить ее в объект типа std::string.

Вот как может выглядеть запись значения объекта типа std::string в файл, а затем чтение его из файла

#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;
    }
}

Вывод программы на консоль

n = 12
IWProgrammer
READ ALSO
Массив структуры [требует правки]

Массив структуры [требует правки]

Разработайте структуру для хранения данных о цветном кружке:

278
После компиляции трансляция?

После компиляции трансляция?

Изучаю WinApi, столкнулся в одной книге с таким описанием:

285
Функция со switch с переменным количеством case

Функция со switch с переменным количеством case

Допустим, у меня есть несколько таких блоков:

321
ImageMagick C++ API бинарное (1 bit per pixel) изображение

ImageMagick C++ API бинарное (1 bit per pixel) изображение

Существует ли возможность создания 1-битных изображений и конвертации в этот формат изображений иных форматов с помощью библиотеки imagemagick?...

313