读取文本文件时出现分段错误
Segmentation fault when reading text file
我正在尝试 运行 从文本文件中对泰坦尼克号幸存者的年龄进行排序的代码。它编译得很好,但是当我选择选项 B(选项 A 尚未写入)时,程序只是简单地说“分段错误”而终止。
这是文本文件的一个小样本以供参考。
29 1stClass TRUE
0.9 一级真
2 一级错误
30 一级错误
我已经将错误隔离到处理文件的块(//实际处理),但我不确定到底是什么地方出了问题。
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <fstream>
#include <ctype.h>
void sortSurvivors();
void sortAgesLiving();
int main()
{
char options;
std::cout << "Titanic Data \nOptions \nA) Display count of people who lived and died... \nB) Display count of people who lived by age... \nPlease select option (A-B)...";
std::cin >> options;
switch (options)
{
case 'A':
sortSurvivors();
break;
case 'B':
sortAgesLiving();
break;
}
}
void sortSurvivors()
{
}
void sortAgesLiving()
{
std::ifstream inputFile;
std::string filename = "TitanicData.txt";
std::string age;
std::string classBoat;
std::string survival;
bool survived;
int eldest = 0;
//pre-sort processing
while (inputFile >> age >> classBoat >> survival)
{
int ageConv = stoi(age);
//G is for the ghetto fix I am pulling here, because I recieve an error when using "TRUE" as a string
char gchar = 'G';
survival += gchar;
if (survival == "TRUEG")
{
survived = true;
}
else
{
survived = false;
}
if (eldest < ageConv)
{
eldest = ageConv;
}
}
//initialize vector
std::vector<int> survivorVector;
for (int i = 0; i < eldest; i++)
{
survivorVector.push_back(0);
}
inputFile.open(filename);
//actual processing (ERROR HERE)
if (inputFile)
{
while (inputFile >> age >> classBoat >> survival)
{
int ageConv = stoi(age);
if (survived = true)
{
survivorVector[ageConv] = survivorVector[ageConv] + 1;
}
for (int j = 0; j <= eldest; j++)
{
std::cout << j << "\t" << survivorVector[j] << "\n";
}
}
// Close the file.
inputFile.close();
}
else
{
std::cout << "I don't know what broke, but uhhhhhhhhhh oops.";
}
}
像往常一样,我确定这是我忽略的愚蠢问题。
在 sortAgesLiving()
中,您忘记在开始排序前处理之前打开文件。因此,您的第一个阅读循环将无法阅读任何内容。因此 eldest
将保持为 0。
然后您构造一个向量并填充它。但由于循环基于 eldest
,向量 survivorVector
将保持为空。
当您最终打开文件并阅读它时,第一行将被视为幸存者,因为您不小心用 true 覆盖了布尔值(即 if (survived = true)
而不是 if (survived == true)
或只是 if (survived)
。然后您将尝试越界访问向量。
即使您更正了这个错误,在第一个幸存者处您还是会再次出界。越界访问向量是 UB,许多可能的症状之一可能是分段错误。
杂项建议(与您的问题无关):
- 您的年龄不明确
0.9
。将其转换为 int
会导致它为 0。这样可以吗,还是需要四舍五入?
- 如果是四舍五入的话,可以把年龄变量做成
double
,直接读取,不用转换。然后,您可以根据需要将其数学转换为整数年龄,将其四舍五入或截断。如果你确定只有整数,你可以使变量成为 int
而根本不用担心。
- 信任文件中的值来直接索引向量是不安全的。如果在两个读取阶段之间,其他人向文件添加了一个值高于
eldest
的附加行怎么办?如果读取的值是负数怎么办?在将值用作索引之前,最好始终检查它是否在可接受的范围内。它可以为您节省数小时的调试时间,并为您的客户节省一些噩梦。
- 最后,两阶段读取不是必需的:您可以只读取年龄,并在检查它为正且小于 150 年(相当乐观)后,如果需要,您可以调整向量的大小,如果年龄等于或大于当前矢量大小。为什么?想象一下,有一天你为美国人口普查工作,文件有数百万行:文件越少越好;-)
我正在尝试 运行 从文本文件中对泰坦尼克号幸存者的年龄进行排序的代码。它编译得很好,但是当我选择选项 B(选项 A 尚未写入)时,程序只是简单地说“分段错误”而终止。 这是文本文件的一个小样本以供参考。
29 1stClass TRUE
0.9 一级真
2 一级错误
30 一级错误
我已经将错误隔离到处理文件的块(//实际处理),但我不确定到底是什么地方出了问题。
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <fstream>
#include <ctype.h>
void sortSurvivors();
void sortAgesLiving();
int main()
{
char options;
std::cout << "Titanic Data \nOptions \nA) Display count of people who lived and died... \nB) Display count of people who lived by age... \nPlease select option (A-B)...";
std::cin >> options;
switch (options)
{
case 'A':
sortSurvivors();
break;
case 'B':
sortAgesLiving();
break;
}
}
void sortSurvivors()
{
}
void sortAgesLiving()
{
std::ifstream inputFile;
std::string filename = "TitanicData.txt";
std::string age;
std::string classBoat;
std::string survival;
bool survived;
int eldest = 0;
//pre-sort processing
while (inputFile >> age >> classBoat >> survival)
{
int ageConv = stoi(age);
//G is for the ghetto fix I am pulling here, because I recieve an error when using "TRUE" as a string
char gchar = 'G';
survival += gchar;
if (survival == "TRUEG")
{
survived = true;
}
else
{
survived = false;
}
if (eldest < ageConv)
{
eldest = ageConv;
}
}
//initialize vector
std::vector<int> survivorVector;
for (int i = 0; i < eldest; i++)
{
survivorVector.push_back(0);
}
inputFile.open(filename);
//actual processing (ERROR HERE)
if (inputFile)
{
while (inputFile >> age >> classBoat >> survival)
{
int ageConv = stoi(age);
if (survived = true)
{
survivorVector[ageConv] = survivorVector[ageConv] + 1;
}
for (int j = 0; j <= eldest; j++)
{
std::cout << j << "\t" << survivorVector[j] << "\n";
}
}
// Close the file.
inputFile.close();
}
else
{
std::cout << "I don't know what broke, but uhhhhhhhhhh oops.";
}
}
像往常一样,我确定这是我忽略的愚蠢问题。
在 sortAgesLiving()
中,您忘记在开始排序前处理之前打开文件。因此,您的第一个阅读循环将无法阅读任何内容。因此 eldest
将保持为 0。
然后您构造一个向量并填充它。但由于循环基于 eldest
,向量 survivorVector
将保持为空。
当您最终打开文件并阅读它时,第一行将被视为幸存者,因为您不小心用 true 覆盖了布尔值(即 if (survived = true)
而不是 if (survived == true)
或只是 if (survived)
。然后您将尝试越界访问向量。
即使您更正了这个错误,在第一个幸存者处您还是会再次出界。越界访问向量是 UB,许多可能的症状之一可能是分段错误。
杂项建议(与您的问题无关):
- 您的年龄不明确
0.9
。将其转换为int
会导致它为 0。这样可以吗,还是需要四舍五入? - 如果是四舍五入的话,可以把年龄变量做成
double
,直接读取,不用转换。然后,您可以根据需要将其数学转换为整数年龄,将其四舍五入或截断。如果你确定只有整数,你可以使变量成为int
而根本不用担心。 - 信任文件中的值来直接索引向量是不安全的。如果在两个读取阶段之间,其他人向文件添加了一个值高于
eldest
的附加行怎么办?如果读取的值是负数怎么办?在将值用作索引之前,最好始终检查它是否在可接受的范围内。它可以为您节省数小时的调试时间,并为您的客户节省一些噩梦。 - 最后,两阶段读取不是必需的:您可以只读取年龄,并在检查它为正且小于 150 年(相当乐观)后,如果需要,您可以调整向量的大小,如果年龄等于或大于当前矢量大小。为什么?想象一下,有一天你为美国人口普查工作,文件有数百万行:文件越少越好;-)