Ошибка сегментации с использованием векторов в C ++? - PullRequest
0 голосов
/ 10 июля 2019

Последние 3 часа я ищу ошибку сегментации, которую я запрограммировал в своем коде. Это в основном появляется, когда моя функция parseRecord (string) генерирует вектор и если я хочу распечатать один из элементов. Я сузил его до этого момента, но не могу найти ошибку. Векторы являются объектами записи, которые создаются путем чтения файла, в каждой строке которого содержится по одной строке данных.

Я надеюсь, что кто-то может мне помочь

Всякий раз, когда я создаю Объект класса (без создания вектора), я могу напечатать элемент очень хорошо. Он появляется только всякий раз, когда я использую функцию parseRecord (string), которая создает вектор.

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

#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>

#include "record.hpp"

ifstream parsefile(string filename);
std::vector<Record> parseRecord(string line);

int main(int argc, char const *argv[])
{
    std::vector<Record> dataSet = parseRecord("data.dat");

    Record record("D11101001", "Max", "Muestermann",
                  10239, "fictionalmarkt.com", "23.12.19", "11:11:00");

    cout << record;

    for(std::vector<Record>::const_iterator i = dataSet.begin(); i != dataSet.end(); ++i){
        cout << *i << endl;
    }
    return 0;
}

//METHOD-IMPLEMENTATION
//parse-file definition - Test if file is accessible
ifstream parsefile(string filename)
{
    ifstream inFile(filename);
    if (!inFile)
    {
        cerr << "File could not be opened" << endl;
        exit(-1);
    }
    cout << "Input-file is readable!" << endl;
    return inFile;
}

//parse-record definition - read file, add to vector<Record> and return vector
std::vector<Record> parseRecord(string filename)
{
    vector<Record> dataSet;

    ifstream inFile = parsefile(filename);
    string line;

    while (getline(inFile, line))
    {
        stringstream linestream(line);
        string accountNb;
        string firstName;
        string lastName;
        string amountStr; //format 100 = 1.00€
        string merchant;
        string date;
        string time;
        long double amount;

        getline(linestream, accountNb, '|');
        getline(linestream, firstName, '|');
        getline(linestream, lastName, '|');
        getline(linestream, amountStr, '|');
        getline(linestream, merchant, '|');
        getline(linestream, date, '|');
        getline(linestream, time, '\n');

        try
        {
            amount = stold(amountStr);
        }
        catch (const std::exception &e)
        {
            std::cerr << e.what() << '\n'
                      << "Conversion error";
        }

        amount *= 100.0; //to correct the decimal format

        Record recordEntry(accountNb, firstName, lastName, amount, merchant, date, time);

        //cout << recordEntry << endl;

        dataSet.push_back(recordEntry);
    }

    return dataSet;
}

record.hpp

class Record
{
private:
    string accountNb;
    string firstName;
    string lastName;
    long double amount; //format 100 = 1.00€
    string merchant;
    string date;
    string time;
public:
    Record(string, string, string, long double, string, string, string);
    ~Record();
    friend ostream& operator<<(ostream&, const Record&);
};

record.cpp

#include "record.hpp"
#include <ostream>

Record::Record(string accountNb, string firstName, string lastName,
               long double amount, string merchant, string date, string time)
{
    this->accountNb = accountNb;
    this->firstName = firstName;
    this->lastName = lastName;
    this->amount = amount;
    this->merchant = merchant;
    this->date = date;
    this->time = time;
}

Record::~Record()
{
}

ostream &operator<<(ostream &os, const Record &rec)
{
    os << right;
    os << setw(15) << "Account Nb:" << setw(50) << rec.getAccountNb() << endl;
    os << setw(15) << "First Name:" << setw(50) << rec.getFirstName() << endl;
    os << setw(15) << "Last Name:" << setw(50) << rec.getLastName() << endl;
    try
    {
        os << showbase;
        os << setw(15) << "Amount:" << setw(50);
        os.imbue(std::locale("de_DE.UTF-8"));
        os << put_money(rec.getAmount(), true) << endl;
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << "locale not supported system";
    }
    os << setw(15) << "Merchant:" << setw(50) << rec.getMerchant() << endl;
    os << setw(15) << "Date:" << setw(50) << rec.getDate() << endl;
    os << setw(15) << "Time:" << setw(50) << rec.getTime() << endl;
}

В результате консоль печатает:

Account Nb:                                         D11101001
First Name:                                               Max
 Last Name:                                       Muestermann
    Amount:                                       102,39 EUR
First Name:                                             Jonny
 Last Name:                                               Doe
    Amount:                                        80,38 EUR
  Merchant:                                          markt.de
      Date:                                          25.12.19
      Time:                                         11:11:19
Segmentation fault (core dumped)

Так что он выходит после первого ряда.

1 Ответ

3 голосов
/ 10 июля 2019

Одна ошибка в том, что вы не возвращаете значение из этой функции:

ostream &operator<<(ostream &os, const Record &rec)

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

ostream &operator<<(ostream &os, const Record &rec)
{
    //...
    return os; // <-- you are missing this line
}

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

double amount;  // <--uninitialized.
//..
try
{
   amount = stold(amountStr);
}
catch (const std::exception &e)
{
   std::cerr << e.what() << '\n' << "Conversion error";
}

amount *= 100.0; // <-- behavior undefined if exception above this line was thrown.
...