Fstream infinite loop while reading file in C ++

I am in class CS101 at my school using C ++. I have a program that needs to read a file in this format:

Ramirez, Manny
1572838992 a 4 b 5 x 4 a 7 c 3 c 4 *
Kemp, Matt
3337474858 a 4 b 4 b 4 a 4 *

      

It is supposed to read the file, calculate the GPA of each student, and output the student's name, ID, units, and GPA. For a while, I tried different things several times and I went back and forth with endless loops. I got help from a friend who I had some stuff.

I've tried changing the loop condition inside the while (! Eof) loop so many times that I cannot count them all. Every time I look at what to do online, the advice I get is just not to use it yet! Eof because it has a penchant for creating infinite loops. Well, I know this now, but my professor wants us to do this.

Here is my code:

 #include <iostream>
    #include <fstream>
    #include <string>
    #include <iomanip>
    #include <sstream>
    using namespace std;
    int main() {

    char grade;
    int units=0, studentsGrade=0, studentUnits=0;
    int unitTotal=0;
    float gradeTotal=0, gpa = 0;
    string inputName, outputName, fullName;
    long ID;
    ifstream inputFile;
    ofstream outputFile;

    cout << "Please enter the input filename: ";
    cin >> inputName;
    cout << "Please enter the output filename: ";
    cin >> outputName;
    inputFile.open(inputName.c_str());
    if (inputFile.fail()) 
        cout << "Bad input file name." << endl;
    else {
    outputFile.open(outputName.c_str());
    outputFile << left << setw(25) << "Name" << setw(15) << "ID" << setw(15)
    << "Units" << setw(15) << "GPA" << endl;
    outputFile << "--------------------------------------------------------------------------------" << endl;
    cout << left << setw(25) << "Name" << setw(15) << "ID" << setw(15)
    << "Units" << setw(15) << "GPA" << endl;
    cout << "--------------------------------------------------------------------------------" << endl;





    getline(inputFile, fullName);
    while (!inputFile.eof()) {
        gpa = 0;
        unitTotal = 0;
        gradeTotal = 0;
        inputFile >> ID;
        outputFile << setw(25) << fullName;
        outputFile << setw(15) << ID;
        cout << setw(25) << fullName << setw(15) << ID;
        string line;
        getline(inputFile,line);
        istringstream iss(line);
        while (!iss.eof()) {
            units = 0;
            iss >> grade >> units;
            if (grade == '*')
                break;
            if (units > 0 && units <=5 && (grade == 'a' || grade == 'A')) {
                gradeTotal += 4 * units;
                studentsGrade += 4 * units;
                unitTotal += units; 
                studentUnits += units;}
            else if (units > 0 && units <=5 && (grade == 'b' || grade == 'B')) {
                gradeTotal += 3 * units;
                studentsGrade += 3 * units;
                unitTotal += units;
                studentUnits += units; }
            else if (units > 0 && units <=5 && (grade == 'c' || grade == 'C')) {
                gradeTotal += 2 * units;
                studentsGrade += 2 * units;
                unitTotal += units;
                studentUnits += units; }
            else if (units > 0 && units <=5 && (grade == 'd' || grade == 'D')) {
                gradeTotal += 1 * units;
                studentsGrade += 1 * units;
                unitTotal += units;
                studentUnits += units; }
            else if (units > 0 && units <=5 && (grade == 'f' || grade == 'F')) {
                unitTotal += units;
                studentUnits += units; }
            else if (grade == '*') {
                unitTotal += 0;}
            else {
                unitTotal += 0; }
        } 
        gpa = (float)gradeTotal / unitTotal;
        outputFile << fixed << showpoint;
        outputFile << setw(15) << unitTotal << setw(15) << setprecision(2) << gpa << endl;
        cout << fixed << showpoint;
        cout << setw(15) << unitTotal << setw(15) << setprecision(2) << gpa << endl;
        getline(inputFile,fullName);
        }
    outputFile << "The GPA for all students is " << setprecision(2) << (float)studentsGrade / studentUnits;
    cout << "The GPA for all students is " << setprecision(2) << (float)studentsGrade / studentUnits << endl;

}
    inputFile.close();
    outputFile.close();
    cout << endl;
    return 0;
    }

      

If anyone can explain to me why I keep getting an infinite loop, I would really appreciate it.

+3


source to share


2 answers


While this needs to be verified by running the code, it seems that you get failbit

either badbit

, but not eof

. This can happen, for example, after other readings, and not getline()

- for example inputFile >> ID;

.

Since you are only checking eof

, the loop runs indefinitely and I / O errors are ignored. I would try using the result getline()

and use operator void*

for std::istream

instead of checking eof()

.

If your professor only wants you to use eof()

, then try a workaround error checking. The solution might be to use special values ​​and assume that if the read operation did not set a value for something else, then it failed and exited the loop. For example, set ID

in before reading LONG_MAX

and make sure it is not LONG_MAX

after.



Finally - just run the code under the debugger on a small working dataset, go over and see what happens. Get to know yourself with a debugger and learn troubleshooting skills. This will surely save you a lot of time throughout your career.

See also - http://www.cplusplus.com/reference/iostream/ifstream/

Good luck!

+4


source


Checking for eof is not enough. You also need to check the result of your read functions, at least at critical points, such as after reading a value. For example, there may be a space at the end of the file. You can test if (cout.fail())

for this.

Better if you can find a way to record the part that starts here:

if (units > 0 && units <=5 && (grade == 'a' || grade == 'A')) {

      



like a loop with a body like this:

        gradeTotal += i * units;
        studentsGrade += i * units;
        unitTotal += units; 
        studentUnits += units;

      

+1


source