-1

我正在为我的 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 参数中的一个,我会得到相同的错误。我猜这要么与我制作的结构有关,要么与我过度使用的复杂性有关。

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

4

2 回答 2

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);
于 2013-01-23T22:20:29.200 回答
1

根据您的代码立即想到的两个问题。首先,当您创建一个向量时,例如studentList默认大小和容量均为 0。然后当您访问该向量时,就像studentList[index]您访问向量的末尾并覆盖一些随机内存一样。

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

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

希望有帮助!

于 2013-01-23T22:23:08.233 回答