0

I am having trouble reading a file to my class object's members. It says it cannot read the file.

This is my class:

const int SIZE_OF = 5;

class Student
{
public:
    Student();
    Student(const Student &);
    Student(string, int, int, int, int, int);
    friend std::istream& operator >> (std::istream& in, Student& S);
    void display();
private:
    string lastName;
    int grades[SIZE_OF];
};

The cpp file associated with my class object to define the functions:

#include "Student.h"

Student::Student()
{
    int i;
    string lastName = "default";
    for (i = 0; i < 5; i++)
    {
        grades[i] = 0;
    }

}

Student::Student(const Student & S)
{
    int i;
    lastName = S.lastName;
    for (i = 0; i < 5; i++)
    {
        grades[i] = S.grades[i];
    }
}

Student::Student(string S, int a, int b, int c, int d, int e)
{
    lastName = S;
    grades[0] = a;
    grades[1] = b;
    grades[2] = c;
    grades[3] = d;
    grades[4] = e;
}

std::istream& operator >> (std::istream& in, Student& S)
{
    char dummy;
    in >> S.lastName >> S.grades[0]
        >> dummy >> S.grades[1]
        >> dummy >> S.grades[2]
        >> dummy >> S.grades[3]
        >> dummy >> S.grades[4];
    return in;

}

void Student::display()
{
    int i;
    int sum = 0;
    double average;
    cout << "Last Name: " << lastName << endl;
    cout << "Grades: " << endl;
    for (i = 0; i < 5; i++)
    {
        cout << grades[i] << endl;
    }
    for (i = 0; i < 5; i++)
    {
        sum = sum + grades[i];
    }
    average = sum / 5;
    cout << "Average: " << average;

}

And finally, the main function that I have so far to test the file opening and reading it to the various variables inside the class.

void main()
{
    fstream     File;
    string      FileName = "ProgramSixData.txt";
    bool        FoundFile;
    string      Line;
    Student     testStudent;

    do {
        File.open(FileName, ios_base::in | ios_base::out);
        FoundFile = File.is_open();
        if (!FoundFile)
        {
            cout << "Could not open file named " << FileName << endl;
            File.open(FileName, ios_base::out); // try to create it
            FoundFile = File.is_open();
            if (!FoundFile)
            {
                cout << "Could not create file named " << FileName << endl;
                exit(0);
            }
            else;
        }
        else;
    } while (!FoundFile);
    do {
        File >> testStudent;
        if (File.fail())
        {
            cout << "Read Failed" << endl;
            cout << "Bye" << endl;
            exit(0);
        }
        else;
        testStudent.display();
    } while (!File.eof());
    cout << "Bye" << endl;
    File.close();
}

The text document that I am reading from is the following:

George
75,85,95,100,44
Peter
100,100,100,100,100
Frank
44,55,66,77,88
Alfred
99,88,77,66,55

How do I save each of the names and the associated 5 grades to a particular object of the student class?

Teja S
  • 1
  • 3
  • 2
    What is the exact error you are getting? – πάντα ῥεῖ Jul 21 '16 at 23:26
  • What is not working out exactly? Also an if statement does not necessarily need an else.. – Julian Declercq Jul 21 '16 at 23:28
  • In my main statement I have it read out "read failed" if it encounters File.fail() and that is what is happening. – Teja S Jul 21 '16 at 23:30
  • 1
    @TejaS _`while (!File.eof());`_ [looks wrong](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – πάντα ῥεῖ Jul 21 '16 at 23:33
  • The issue is that my file is not being read into the class object's variables. There may be something written wrong? – Teja S Jul 21 '16 at 23:53
  • When you write code, start with something simple that works perfectly, then build up slowly. Try reading a file of `int` before you attempt a file of `Student`. – Beta Jul 22 '16 at 00:15
  • Seems no special issue with the program, and I could run it on my machine. The issue may be that the file does not exist in the working directory, you may specify FileName as "d:\\ProgramSixData.txt" and put the data in d:\ to try again. And also the first File.open is intended for only read, so you could remove the ios::out. Change do-while to while as suggested by πάντα ῥεῖ is also right, to handle empty file case. – Ranger Wu Jul 22 '16 at 01:42

1 Answers1

0

You are digging too deep. I made an example solution for you, focusing on the parsing. Things could be way shorter and we could instantly make the students instead of doing it the map way, but I want you to understand how to parse the file, because that is obviously what you are struggling with. Ask me anything about the code if you don't understand it.

void main()
{
    string      FileName = "ProgramSixData.txt";
    bool        FoundFile;
    string      Line;
    vector<Student> Students;

    ifstream file(FileName); //an ifstream is an INPUTstream (same as a fstream with ::in flag. Passing the FileName as argument opens that file
    if (file.fail()) //check if the file opened correctly
    {
        cout << "Failed to open inputfile\n";
        return;
    }

    map <string, vector<int>> studentAndGrades; //map is a container that uses keys and values, every key has a value, we will use the name of the student as the key to access his marks (a vector of int)
    vector<string> allLines;
    string line;
    while (file >> line) //these 2 linessimply reads ALL the lines to the allLines vector
        allLines.push_back(line);

    for (size_t i = 0; i < allLines.size(); i += 2) //loop over all lines, by 2 at a time (1 for the students name and 1 for his marks)
    {
        vector<int> numbers;

        size_t lastCommaIdx = 0;
        size_t currentCount = 0;
        string scores(allLines[i + 1]); //make a copy of allLines[i + 1] for convenient use
        bool firstLine = true;
        for (size_t i = 0; i < scores.size(); ++i) //following code is just to split the numbers from the comma's and put them in a vector of int
        {
            if (scores[i] == ',')
            {
                if (firstLine)
                {
                    numbers.push_back(stoi(scores.substr(lastCommaIdx, currentCount)));
                    firstLine = false;
                }
                else
                {
                    numbers.push_back(stoi(scores.substr(lastCommaIdx + 1, currentCount)));
                }
                lastCommaIdx = i;
                currentCount = 0;
            }
            else
            {
                ++currentCount;
            }
        }
        numbers.push_back(stoi(scores.substr(lastCommaIdx + 1))); //last number
        studentAndGrades.insert(make_pair(allLines[i], numbers)); //finally, insert them in the map
    }

    for (const auto& student : studentAndGrades)
        Students.push_back(Student(student.first, student.second[0], student.second[1], student.second[2], student.second[3], student.second[4])); //make students from the information that we read into the map

    for (auto& student : Students) //display all students with a range based for loop
        student.display();
    file.close();
}
Julian Declercq
  • 1,356
  • 2
  • 14
  • 29
  • I'm getting indentifier map is undefined? Sorry I'm a beginner at C++ so I don't know how that works. – Teja S Jul 22 '16 at 00:10
  • I added the map header file but the stuff written there is all way over my head. I just need a basic method of reading from the file which my file which is not doing even though my file is opening. – Teja S Jul 22 '16 at 00:13
  • @TejaS Allright, let me add some explanation for you then :) – Julian Declercq Jul 22 '16 at 07:57
  • @TejaS I added a lot of explanation, try to understand everything and if you get stuck, just ask. – Julian Declercq Jul 22 '16 at 08:01