Search code examples
c++stringfilefilestreamstringstream

Code outputs nonsense to output file instead of string?


The following code is for a project I have to do where I recieve a text file that has a students first and last name followed by his grades. I then have to convert that into an output file that contains his name followed by his average score. The file I recieve has multiple students in it spereated line by line. The output should look relativly like

Rzam, Look           = 0.00
Bambi, Lambi         = 40.47
Coop, Jason          = 27.31

but mine is merely printing garbage such as

0x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.000x7fffb08e8698= 0.00

Here is what I have so far:

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

using namespace std;

struct Student
{
    string fname;
    string lname;
    double average;
};

int read(ifstream &fin, Student s[]);

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


int main()
{
    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;
    cout << endl;

    fin.open(inputFile.c_str());
    fout.open(outputFile.c_str());

    read(fin , s);
    print(fout, s, size);

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

}

int read(ifstream &fin, Student s[])
{
    string line;
    string firstName;
    string lastName;
    double score;
    double total;
    int i=0;
    int totalStudents=0;
    Student stu;

    while(getline(fin, line)){
        istringstream sin;
        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++;
    }
    return totalStudents;
}

void print(ofstream &fout, Student s[], int amount)
{
    ostringstream sout;
    for(int i = 0; i<amount; i++)
    {
        sout << left << setw(20) << s[i].lname << ", " << s[i].fname;
        fout << sout << setprecision(2) << fixed << "= " << s[i].average;
    }
}

Solution

  • You have a few bugs, which have added up to your issue:

    1. in your print function, you write to a ostringstream and then try to write that to the file stream. Which is fine, but it is printing the address of the ostringstream buffer. So making this change will cause it to print the contents:

      fout << sout.str() << setprecision(2) << fixed << "= " << s[i].average;
      

    Note the usage of .str(). Though you don't really need a temporary stream here at all...

    1. You don't place a newline in the output, so it all ends up one line making it hard to read:

    so make another change making it look like this:

    fout << sout.str() << setprecision(2) << fixed << "= " << s[i].average << '\n';
    
    1. You need to place the ostringstream sout; inside the loop, so it is reset each time too. Otherwise you will get weirdly compounding output.

    2. You don't use the count of students calculated by your read function! so it always tries to print 10! Do something like this:

      int count = read(fin , s);
      print(fout, s, count);
      
    3. If no score is read, I think you'll have a divide by zero. So you should add a check.

    4. You should ensure that no more than size Students are read. Or better yet, just place them in a std::vector and return that from the function. It's simpler and less error prone.

    5. You need to reset i each time you start reading a student, or the later students will get divided by way too much. Each needs to have an independent count.

    I don't know if these are the only issues, but certainly it should get you started on the right track :-)