Reading data from text file into a dynamic array of structs

Hello, I am having some trouble reading my data into a dynamic array of structs. Below is my code as well as a copy of the text file. While debugging, I see that as the !fin.eof loops, no data is being stored into the array, named record. I am new to dynamic arrays, am I wrong on my approach here?


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
12
John Milligan
3 CIS100 CIS105 MAT113
Jill Kerning
5 CIS100 CIS105 MAT232 BIO100 ENG101
Aaron Spencer
4 CIS201 CIS225 MAT232 ENG101
Damon Hill
2 CIS334 CIS400
Kaitlyn Stamen
4 CIS100 CIS10 MAT113 BIO100
Debbie Martin
5 CIS100 CIS105 MAT232 CHY112 ENG101
Greg Nolan
2 CIS334 CIS450
Lynn Sanders
4 CIS334 CIS450 MAT250 BIO100
Alicia Thomas
4 CIS226 CIS450 MAT232 CHY112
Alan Turner
5 CIS100 CIS105 MAT232 BIO100 ENG101
Paul Henley
5 CIS100 CIS105 CIS334 ENG101 MAT232
Tim Copeland
1 CIS450


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
28
29
30
31
32
33
34
35
36
37
  #include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>

using namespace std;

struct Records	//struct definition
{
	string name;
	int numCourses;
	string courseCode;
};

int main()
{
	int size;
	int count = 0;
	ifstream fin;

	fin.open("courses.txt");
	fin >> size; //returns the first line of the document containing array size

	Records* record = new Records[size]; //Dynamic allocation of array

	while (!fin.eof()) {			//while not end of report, do the following:
		getline(fin, record[count].name);
		fin >> record[count].numCourses;
		getline(fin, record[count].courseCode);
		count++;
	}

	fin.close();
	delete[] record;
    return 0;
It's not a good idea to use eof() as the loop condition. It can cause a number of different issues, the first of which you discovered, the possibility of an infinite loop.

We can take a first attempt at fixing the code by changing the loop condition as follows:
1
2
3
4
5
6
7
8
    // while array is not filled, do the following:
    while (count < size)
    {            
        getline(fin, record[count].name);
        fin >> record[count].numCourses;
        getline(fin, record[count].courseCode);
        count++;
    }

That should tame the never-ending looping.

But there are a few other things to be fixed too.

One, we do need to check the file status after reading from it. Otherwise, say the rest of the file was empty and all the inputs failed, the loop would just continue regardless.

Two, when mixing getline() with the extraction operator >> there can be some problems with things getting out of synchronisation. A common solution is to use ignore() to read and discard either a single character, or everything up to the end of the current line. In particular, after the first input, fin >> size; the rest of the line needs to be discarded, or else the next getline will read an empty line instead of the student name.

Here's a version of the code with various changes made as summarised above:
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>

using namespace std;

struct Record  // struct definition
{
    string name;
    int numCourses;
    string courseCode;
};

int main()
{
    int size;
    int count = 0;
    ifstream fin("courses.txt");
    fin >> size; // read an integer from the file, containing array size
    if (!fin)
    {
        cout << "Could not read number of students from file\n";
        return 1;
    }
    fin.ignore(1000, '\n'); // ignore everything until end of line

    Record* record = new Record[size]; // Dynamic allocation of array

    // while array is not filled AND the file status is good
    // do the following:
    while (count < size && fin)
    {            
        getline(fin, record[count].name);
        fin >> record[count].numCourses;
        fin.ignore(); // ignore a single character
        getline(fin, record[count].courseCode);
        if (fin)     // add 1 to count if the file access was successful
            count++;
    }

    fin.close();
    
    cout << "count = " << count << '\n';
    
    for (int i=0; i<count; i++)
    {
        cout << "Name: " << record[i].name
             << "\nNumber of courses: " << record[i].numCourses
             << "\nCourse code: " << record[i].courseCode 
             << '\n';
    }
    
    delete[] record;
    return 0;
}



Topic archived. No new replies allowed.