Reading in values from txt files

Hi there, I cant seem to read stuff in from my students.txt file which contains this

19992195 John Smith 20 05 1995 09 09 2011 15 05 2014 55 65 72 58 80 45 40 45 66 78 88 81
20051195 Mark Dobson 20 05 1995 09 09 2011 15 05 2014 55 65 72 58 80 45 40 45 66 78 88 81
20063196 Paula O'Reilly 20 05 1995 09 09 2011 15 05 2014 55 65 72 58 80 45 40 45 66 78 88 81
20053344 Aoife Cleary 20 05 1995 09 09 2011 15 05 2014 55 65 72 58 80 45 40 45 66 78 88 81


It has something to do with the lines at the bottom of the code. Can anyone help me? It doesnt cout anything. The program just crashes upon execution. First, it asks me the amount of students i want to handle. I enter '1'. Then it asks me if i want to read in from external file and i enter 'Y'. then the exe just crashes, can anyone help?



#include <iostream>
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct Date
{
int day, month, year;
};


struct Grade
{
int score[6];
};

struct Student
{
bool free;
long studentID;
string fname;
string sname;
Date DOB, DOE, DOG;
Grade semester1, semester2;
};

void initialise_database(vector<Student>, int size); // initialize each free variable to free
int menu();
void add_students(vector<Student>, int size);
void display_students(vector<Student>, int size);

int main(int argc, char** argv)
{
fstream fin;
char choice_readfile;
int rowcount;

int size;
cout << "Enter number of students that you wish to keep in record:\n";
cin >> size;

vector<Student> BENG;


do //verify choice to read from file is Y,y or N,n
{
cout << "Do you wish to read from file (Y/N)? (file name must be named students.txt)" << endl; //choice for user to read from external file
cin >> choice_readfile;
while(cin.fail())
{
cin.clear();
cin.ignore(80,'\n');
cout << "Please Re-Enter choice" << endl;
cin >> choice_readfile; // choice to read from file
}
}
while(choice_readfile != 'Y' && choice_readfile != 'y' && choice_readfile != 'N' && choice_readfile != 'n');

if(choice_readfile == 'Y' || choice_readfile == 'y')
{
fin.open("students.txt", ios::in|ios::out); //opens mygrades.txt
if(fin.fail())
{
cout << "Error occured while opening students.txt" << endl;
exit(1);
}
fin.clear();
fin.seekg(0);

string line;
while( getline(fin, line) ) //counts the rows in the external file
{
rowcount++;
}
fin.clear();
fin.seekg(0);

cout << "Number of rows in file is " << rowcount << endl;
cout << size << " " << rowcount << endl;
fin.clear();
fin.seekg(0);

int i=0;
while(!fin.eof())
{
fin >> BENG[i].studentID >> BENG[i].fname >> BENG[i].sname >> BENG[i].DOB.day >> BENG[i].DOB.month >> BENG[i].DOB.year >> BENG[i].DOE.day >> BENG[i].DOE.month >> BENG[i].DOE.year >> BENG[i].DOG.day >> BENG[i].DOG.month >> BENG[i].DOG.year >> BENG[i].semester1.score[0] >> BENG[i].semester1.score[1] >> BENG[i].semester1.score[2] >> BENG[i].semester1.score[3] >> BENG[i].semester1.score[4] >> BENG[i].semester1.score[5] >> BENG[i].semester2.score[0] >> BENG[i].semester2.score[1] >> BENG[i].semester2.score[2] >> BENG[i].semester2.score[3] >> BENG[i].semester2.score[4] >> BENG[i].semester2.score[5];
BENG[i].free = false;
i++;
}
cout << BENG[i]/studentID; //to test to see if it displays
}
Last edited on
There are multiple problems with this code.

1) while(!fin.eof()) reads one more time than needed. Do not loop on eof() it does not work like you think. Loop on input operation, or save input in temporary variable and check stream after input.

2) fin >> BENG[i]/*...*/ Your BENG vector contains 0 elements. Precondition for operator[] is that its argument should be non-negative (actually it cannot be negative as it is unsigned) number less than vector size.
Attempt to use invalid index will lead to undefined behavior. You got lucky and your program just crashed.

3) you should not pass vectors by value and expect changes to it reflect on original vector. Nor you shoud pass size of vector alongside it: vector knows its size already.

4) do not threat vectors as arrays. You can remove values from it, add values to it, request size, and use all of this without need to manually resize vector or mark values as "deleted"
Last edited on
Thank you so much! it helped me a lot!
Avoid monolitic code. Separate it in logical parts and reuse them in your code. C++ features: constructors, operator overloading, etc, will help you with this.

Rule of thumb: if a function does not fit on screen, it is too large.

For example several functions from your code after slight refactoring:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main()
{
    const std::string file_request = "Do you wish to read from file (Y/N)? "
                                     "(file name must be named students.txt)\n";
    const std::string repeat_again = "Please Re-Enter choice: ";
    std::vector<Student> BENG;
    if(ask(file_request, repeat_again))
        BENG = load_file();
    switch(menu()) {
    case 1:
        add_students(BENG);
        break;
    case 2:
        display_students(BENG);
        break;
    default:
        std::cout << "Invalid Option:\n";
    }
}

std::vector<Student> load_file(const std::string& filename = "students.txt")
{
    std::ifstream fin(filename);
    if(not fin.is_open())
        std::clog << "Error occured while opening " << filename << '\n';
    return {std::istream_iterator<Student>(fin), std::istream_iterator<Student>()};
}
Topic archived. No new replies allowed.