在 C++ 中使用向量的分段错误?
Posted
技术标签:
【中文标题】在 C++ 中使用向量的分段错误?【英文标题】:Segmentation fault using vectors in C++? 【发布时间】:2019-07-10 15:39:32 【问题描述】:我正在寻找已编入代码的分段错误。当我的函数parseRecord(string)
生成一个向量并且我想打印出其中一个元素时,它基本上会出现。我已将其范围缩小到这一点,但找不到错误。向量是 Record 对象,通过读取文件创建,每行有一行数据。
每当我创建类的对象(不创建向量)时,我都可以很好地打印元素。它只在我使用创建向量的 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&);
;
记录.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)
所以它在第一行之后退出。
【问题讨论】:
当您在main
中打印时,您确定dataSet
的大小>= 2?
你为什么在 for 循环中做cout << dataSet[1]
?
Segmentation fault using vectors in C++?
-- 将[ ]
的用法替换为at()
。我敢打赌,您不再遇到分段错误,而是抛出了实际异常 (std::out_of_range
)。此外,您对无效双精度的异常处理是错误的——您的代码继续运行,就好像没有任何问题一样。
可能错误在操作符Record
ostream &operator<<
-- 你真的应该注意编译器给你的警告。您在这里没有返回值,因此行为未定义。
【参考方案1】:
一个错误是你没有从这个函数返回一个值:
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.
【讨论】:
非常感谢!有用!真的很奇怪,它与直接创建的对象一起工作。只有在将 -Wall 添加到我的 gcc 编译器之后,警告才可见。学过的知识。我的 IDE 也没有显示任何东西。感谢大家的帮助!我想我会再花 3 个小时没有任何结果:/ @THE-E 它与直接创建的对象“工作”,因为您没有链接<<
调用。在循环中你有cout << *it
,它返回一些垃圾,然后,这个表达式的结果与下一个运算符<< endl
链接在一起——这意味着你做[some rubbish] << endl;
。总的来说,UB 一点都不合理,但这是最可能的解释。以上是关于在 C++ 中使用向量的分段错误?的主要内容,如果未能解决你的问题,请参考以下文章