Michael Santoro Michael Santoro - 1 month ago 15
C++ Question

Code can't accept file that exceeds array size?

Below I have my current code for a project I am working on. It is meant to take a file of students and their grades, average the grades, and then place them all back into an output file. The amount of students should not exceed 10, so if there is more than 10 students it should only read the first 10 then reverse the order. My code works perfectly excpepty when given a file with more than 10 students. It appears it is trying to access a part in memory that doesn't exist. I tried getting the code to ignore empty lines, which it should, but that doesn't seem to fix it. My "read" function is where I believe the problem is.

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

using namespace std;

//My student structure that holds the variable for each student object.
struct Student
{
string fname;
string lname;
double average;
};

//Prototyping the functions to read the input file into an array and then reverse it.
int read(ifstream &fin, Student s[]);

void print(ofstream &fout, Student s[], int amount);

void reverse(Student s[], int amount);

int main()
{
//Creating the file streams and global constant for the array and the filling it with I/O.
const int size = 10;
ifstream fin;
ofstream fout;
string inputFile;
string outputFile;
Student s[size];

cout << "Enter input filename: ";
cin >> inputFile;
cout << "Enter output filename: ";
cin >> outputFile;

//opeining the files given by the user and then testing if the opened.
fin.open(inputFile.c_str());
fout.open(outputFile.c_str());

if(fin.fail()) {
cout << "Unable to open input file.\n";
return 1;
}


//calling my 3 functions and then returning to main(). Closing files as well.
int count = read(fin , s);
reverse(s, count);
print(fout, s, count);
count = 0;

fin.close();
fout.close();

}

//This function reads the file given and breaks it up using string stream. It then calculates the averages for each stuent and assigns it to the array.
int read(ifstream &fin, Student s[])
{
istringstream sin;
string line;
string firstName;
string lastName;
double score;
double total;
double i=0;
int totalStudents=0;
Student stu;
for(int j = 0; j < 10; j++){
while(getline(fin, line)){
sin.clear();

if(line.empty())
{
j--;
}else{
sin.str(line);
while(sin >> firstName >> lastName){
stu.fname = firstName;
stu.lname = lastName;

while(sin >> score){
total += score;
i++;
stu.average = (total/i);
}
}
s[totalStudents]=stu;
totalStudents++;
stu.average = 0;
total = 0;
i = 0;

}
}
}

//returning the number of students in the file so it can later be used for the variable of total students.
return totalStudents;
}

//My print function that puts the array into a given output file.
void print(ofstream &fout, Student s[], int amount)
{
for(int i = 0; i<amount; i++)
{
if(s[i].lname.empty())
{
fout<<"No students to report.";
}else{
ostringstream sout;
sout << s[i].lname.c_str() << ", " << s[i].fname.c_str();
fout <<setw(21)<< left << sout.str() << setprecision(2) << fixed << "= " << s[i].average << '\n';
}
}
}

//the function that reverses the order of the students by copying the last student into a temporary variable and casting it to the beggining.
void reverse(Student s[], int amount)
{
Student temp;
for(int i=0; i< amount/2; i++)
{

temp=s[i];
s[i]=s[amount-i-1];
s[amount - i - 1] = temp;
}
}

Answer

It looks to me that after finding the empty line you should try using a continue statement, instead:

for (int j = 0; j < 10; j++) {
    while (getline(fin, line)) {
        sin.clear();

        if (line.empty())
        {
            continue;
        }
        else {
            sin.str(line);
            while (sin >> firstName >> lastName) {
                stu.fname = firstName;
                stu.lname = lastName;

                while (sin >> score) {
                    total += score;
                    i++;
                    stu.average = (total / i);
                }
            }
            s[j] = stu;
            stu.average = 0;
            total = 0;
            i = 0;

        }
    }
}

As per comments, I missed that about the for loop. It can be eliminated altogether and just have the while loop and a counter:

int j = 0;
while (getline(fin, line) && j < 10)
{
    sin.clear();

    if (line.empty())
    {
        continue;
    }
    else
    {
        sin.str(line);
        while (sin >> firstName >> lastName)
        {
            stu.fname = firstName;
            stu.lname = lastName;

            while (sin >> score)
            {
                total += score;
                i++;
                stu.average = (total / i);
            }
        }
        s[j] = stu;
        stu.average = 0;
        total = 0;
        i = 0;
        j++;
    }
}