-1

3 つのファイルを開き、取得したデータに基づいて 4 つ目のファイルに出力を提供する 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

コードに基づいてすぐに頭に浮かぶ 2 つの問題。まず、studentListデフォルトのサイズと容量が両方とも 0 のようなベクトルを作成するとき。その後、ベクトルstudentList[index]の末尾を越えてアクセスし、メモリのランダムな部分を上書きするようにベクトルにアクセスするとき。

学生の最大数がわかっている場合(あなたのようには見えません)、ベクトルを として初期化できますvector<student> studentList(maxNumberOfStudents)。これにより、maxNumberOfStudent エントリを持つベクトルが得られます。各エントリには、すべてのフィールドのデフォルトで構築されたバージョンが含まれます (文字列の場合、それらは空になります)。studentList.push_back(student())または、ベクターに新しいエントリを追加するようなものを使用できます。おそらくそれを行うためのよりクリーンな方法を見つけることができますが、それが一般的な考え方です。

第 2 に、studentListベクトルを関数に渡すときは、参照 ( vector<student>& studentList) で渡す必要があります。がないと、&値渡しになります。つまり、毎回ベクターのコピーを作成することになります。いくつかの関数はベクトルを変更するため、値渡しの場合、コピーは変更されますが、オリジナルは変更されません。

それが役立つことを願っています!

于 2013-01-23T22:23:08.233 に答える
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 に答える