3

I'm in a CS101 class at my school using C++. I have a program that has 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. I have been trying different things for a while now, and I've been going back and forth with infinite loops. I got help from a friend, who had me include some stuff.

I have tried changing the condition of the loop inside the while (!eof) loop so many times I can't count them all. Every time I look up what to do online, the advice I get is just to not use while !eof because it has a propensity to cause infinite loops. Well, I know that now, but my professor wants us to do it that way.

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.

Spencer Moran
  • 2,320
  • 3
  • 13
  • 13

2 Answers2

4

Though it needs to be verified by running the code, it seems like you are getting either failbit or badbit set but not the eof. This may happen, for example, after you do other reads and not getline() - for example inputFile >> ID;.

Since you are only checking for the eof, the loop runs endlessly and I/O errors are getting ignored. I'd say try using the result of getline() and use operator void* of the std::istream instead of checking eof().

If your professor wants you to use eof() only, then try to workaround error checking. The solution could be to use special values and assume that if read operation didn't set the value to something else then it has failed, and break out of the loop. For example, set ID to LONG_MAX before read, and make sure it is not LONG_MAX after.

And after all - just run the code under debugger on a small working data set, step through and see what happens. Get yourself familiar with a debugger, and practice troubleshooting skills. That will for sure save you a lot of time throughout your career.

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

Good luck!

1

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

It will be better if you can find a way to write the part starting here :

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

as a loop with a body like this:

        gradeTotal += i * units;
        studentsGrade += i * units;
        unitTotal += units; 
        studentUnits += units;
perreal
  • 85,397
  • 16
  • 134
  • 168