字符串和文件麻烦

时间:2013-01-23 22:10:42

标签: c++ file-io segmentation-fault

我正在为我的CS课程做一个实验室,该课程涉及打开三个文件,并根据获得的数据向第四个文件提供输出。我遇到了一些问题(我在C ++上相当生疏),代码让我很头疼。我在字符串和分段错误方面遇到了错误

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

using namespace std;

//Necessary objects/structures
struct student {                            //create a structure to contain all data     consistent to the student
    string ID, name, address, phone;
    bool is_In_Query;
    list<string> class_Grade;               //Dynamic list to contain all letter grades since we don't know how many there will be
};

//Prototypes
bool readStudentFile(string, vector<student>);
bool readGradeFile(string, vector<student>);//returning a boolean will report if read was a success
bool readQueryFile(string, vector<student>);
void outputReportFile(string, vector<student>);
float calculateGPA(student);                //Pass all calculations and reading to functions to simplify and manage code
void reportFileError(int);                  //Reports a file error. "1" is Student, "2" is Grade, "3" is Query
int isSame(string, vector<student>);

int main(int argc, const char* argv[])
{
    vector<student> studentList;            //Allow a range in number of students


    if (!readStudentFile("students.txt", studentList)){
        if (!readGradeFile("grades.txt", studentList)){
            if(!readQueryFile("query.txt", studentList))
                outputReportFile("report.txt", studentList);
            else
                reportFileError(3);
        }
        else
            reportFileError(2);
    }
    else
        reportFileError(1);

    return 0;                               //Termination

/*
    if (!readStudentFile(argv[1], studentList)){
        if (!readGradeFile(argv[2], studentList)){
            if(!readQueryFile(argv[3], studentList))
                outputReportFile(argv[4], studentList);
            else
                reportFileError(3);
        }
        else
            reportFileError(2);
    }
    else
        reportFileError(1);

    return 0;                               //Termination
*/
}


bool readStudentFile(string fileToRead, vector<student> studentInfo)
{
    ifstream inFile;
    int index = 0;

    //inFile.open(fileToRead.c_str());            Original opening line
    inFile.open(fileToRead.c_str(), ifstream::in);

    if (!inFile.good())
        return false;
    else while (!inFile.eof()) {            //Read in order
        getline(inFile, studentInfo[index].ID);
        getline(inFile, studentInfo[index].name);
        getline(inFile, studentInfo[index].address);
        getline(inFile, studentInfo[index].phone);
        ++index;                            //We use a prefix to insure that index is incremented BEFORE the jump back to the else-while
    }
    inFile.close();
    return true;
}

bool readGradeFile(string fileToRead, vector<student> studentInfo)
{
    ifstream inFile;
    string temp;
    int sameID = 0;

    inFile.open(fileToRead.c_str(), ifstream::in);

    if (inFile.fail())
        return false;
    else while (!inFile.eof()) {            //Got more? Ok, let's go!
        cin.ignore();                       //The class ID is not necessary for our computation
        getline(inFile, temp);              //Obtain student ID
        sameID = isSame(temp, studentInfo); //Find it in our list of IDs
        if (sameID != -1){                  //If there is a match, get letter grade
            getline(inFile, temp);
            studentInfo[sameID].class_Grade.push_back(temp);
        }
                                            //No match? Ignored.
    }
    inFile.close();
    return true;
}

bool readQueryFile(string fileToRead, vector<student> studentInfo)
{
    ifstream inFile;
    int sameID = 0;
    string temp;

    inFile.open(fileToRead.c_str(), ifstream::in);

    if (inFile.fail())
        return false;
    else while (!inFile.eof()) {
        getline(inFile, temp);
        sameID = isSame(temp, studentInfo); //We get an ID, compare it
        if (sameID != -1)                   //If it's in there, we'll flag it to not report a GPA of 0 due to a bug
            studentInfo[sameID].is_In_Query = true;
    }
    inFile.close();
    return true;
}

void outputReportFile(string fileToWrite, vector<student> studentInfo)
{
    ofstream outFile;

    outFile.open(fileToWrite.c_str(), ifstream::out);
    outFile.setf(ios::fixed | ios::showpoint);

    for(int x = 0; x < studentInfo.size(); x++){
        if (studentInfo[x].is_In_Query){
            outFile << setw(12) << studentInfo[x].ID;
            outFile << fixed << setprecision(2) << setw(7) << calculateGPA(studentInfo[x]);
            outFile << studentInfo[x].name;

        }
    }

    cout << "Finished.\n";
}    

float calculateGPA(student scholar)
{
    float gpa = 0;
    if (scholar.class_Grade.size() == 0)
            return 0;
    else {
        for(list<string>::iterator it = scholar.class_Grade.begin(); it != scholar.class_Grade.end(); ++it)
        {
            if(*it == "A")
                gpa += 4.0;
            else if (*it == "A-")
                gpa += 3.7;
            else if (*it == "B+")
                gpa += 3.4;
            else if (*it == "B")
                gpa += 3.0;
           else if (*it == "B-")
                gpa += 2.7;
            else if (*it == "C+")
                gpa += 2.4;
            else if (*it == "C")
                gpa += 2;
            else if (*it == "C-")
                gpa += 1.7;
            else if (*it == "D+")
                gpa += 1.4;
            else if (*it == "D")
                gpa += 1.0;
            else if (*it == "D-")
                gpa += 0.7;
            else if (*it == "E")
               gpa += 0;
        }
    }
    gpa = gpa / scholar.class_Grade.size();
    return gpa;
}

int isSame(string id, vector<student> studentInfo)
{
    for (int x = 0; x < studentInfo.size(); x++)
    {
        if (id.compare(studentInfo[x].ID) == 0)
            return x;
    }

    return -1;
}

void reportFileError(int report_num)
{
    switch(report_num){
        case 1 :
            cout << "No valid student file" << endl;
            break;
        case 2 :
           cout << "No valid grade file" << endl;
            break;
        case 3 :
            cout << "No valid query file" << endl;
            break;
    }
}

(我希望我把它正确地放在代码块中)

如果我尝试使用预定义文件名或CLI参数中的文件名,我会得到相同的错误。我猜它要么与我制造的结构有关,要么与我过度的复杂性有关。

所有文件都包含在我的代码和可执行文件的目录中

2 个答案:

答案 0 :(得分:1)

您的函数readStudentFile直接写入尚未调整大小的矢量。

你必须在索引之前调整大小:

studentInfo.resize( studentInfo.size() + 1 );
student & record = studentInfo.back();
getline(inFile, record.ID);
getline(inFile, record.name);
getline(inFile, record.address);
getline(inFile, record.phone);

或者创建一个记录并附加它:

student record;
getline(inFile, record.ID);
getline(inFile, record.name);
getline(inFile, record.address);
getline(inFile, record.phone);
studentInfo.push_back(record);

答案 1 :(得分:1)

根据您的代码立即浮现在脑海中的两个问题。首先,当你创建一个像studentList这样的向量时,默认大小和容量都是0.然后当你访问像studentList[index]这样的向量时,你访问超出向量的末尾并覆盖一些随机的记忆。

如果您知道学生的最大数量(看起来不像),那么您可以将矢量初始化为vector<student> studentList(maxNumberOfStudents)。这将为您提供一个带有maxNumberOfStudent条目的向量,其中每个条目包含所有字段的默认构造版本(对于字符串,它们将为空)。或者,您可以使用studentList.push_back(student())之类的内容向向量追加新条目。你可以用更清洁的方式来做到这一点,但这是一般的想法。

其次,将studentList向量传递给函数时,您需要通过引用(vector<student>& studentList)传递它。没有&,你传递的值就意味着你每次都要复制矢量。由于有几个函数修改了向量,如果你通过值传递,你将修改副本,但原始文件将保持不变。

希望有所帮助!