Files with Arrays

Hello all,

I'm having a bit of trouble manipulating a program that I have already written, and could use some guidance.

The program I have written creates an array of structures that gets filled with data that is taken from a txt file. The program then displays the data onto the prompt in a formatted fashion.

Here is the code so far. (It runs with no errors.)

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <string>

using namespace std;

ifstream st_rec;

struct StudentRec
{
    string Name;
    string ID;
    double GPA;
};

 bool read_a_record (StudentRec& srec)
{
    string fName,lName;
    string vID;
    double vGPA;

    if(st_rec.is_open())
    {
        bool recordWasRead = st_rec>>fName>>lName>>vID>>vGPA;
        if(! recordWasRead)
        {
            return false;
        }

        srec.Name=lName+","+fName;
        srec.ID=vID;
        srec.GPA=vGPA;
        return true;
    }

    else
    {
        cout<<"file could not be opened.";
        return false;
    }

}

void print_a_record(StudentRec srec)
{
    cout<<srec.Name<<"\t\t";
    cout<<srec.ID<<"\t\t";
    cout<<srec.GPA<<endl;
}

int main()
{
    int rec_num=0;
    st_rec.open ("StudentRecord.txt");
    StudentRec StudentRec_array[10];
    const int ARRAY_SIZE =10;

    cout<<"No.\tName\t\t\tID\t\tGPA\n";
    cout<<"____________________________________________________\n";
    int i=0;
    while(read_a_record(StudentRec_array[i]))
        {
            if(i<ARRAY_SIZE)
            {
                cout<<++rec_num<<"\t";
                print_a_record(StudentRec_array[i]);
            }
            else
                break;
            i++;
        }
    return 0;
}


I now want to create a new function that opens the file, reads the file, and populates the elements of the array that can be filled by the input file. This function must be called at the beginning of the main function.
I have tried a few different solutions now, but have ended up with tons of errors on each.

Here is the best solution I have so far.

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
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <string>
#include <sstream>

using namespace std;

ifstream st_rec;


struct StudentRec
{
    string Name;
    string ID;
    double GPA;
};

 bool read_a_record (StudentRec& srec)
{
    string fName,lName;
    string vID;
    double vGPA;

    if(st_rec.is_open())
    {
        bool recordWasRead = st_rec>>fName>>lName>>vID>>vGPA;
        if(! recordWasRead)
        {
            return false;
        }

        srec.Name=lName+","+fName;
        srec.ID=vID;
        srec.GPA=vGPA;
        return true;
    }

    else
    {
        cout<<"file could not be opened.";
        return false;
    }

}


void LoadDatabase()
{
    st_rec.open ("StudentRecord.txt");
    const int ARRAY_SIZE =100;
    StudentRec StudentRec_array[ARRAY_SIZE];

    int i=0;
    while(read_a_record(StudentRec_array[i]))
        i++;

}

int main()
{
    LoadDatabase();

return 0;
}


I tried using cout to display a single array element to check if the results were good, but I could not find a place where the program recognized the array.

The only place where StudentRec_Array exists is inside the LoadDatabase function. The moment it reaches the end of the while loop the memory is being freed and the data is not available anymore.

Make it a global variable like you did with st_rec, this way it will be available everywhere.

And there's another thing. You want to pass a pointer to read_a_record, but you are passing a complete structure.

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

#define ARRAY_SIZE 100

typedef struct{
  string Name;
  string ID;
  double GPA;
}StudentRec;


ifstream st_rec;
StudentRec StudentRec_array[ARRAY_SIZE];

bool read_a_record (StudentRec *srec)
{
  // read data from file until end of file
  If(!st_rec.eof())
  {
    ....
  
  
    //srec is a pointer so acces member like this:
    srec->Name = Name;
    srec->ID =ID;
    srec->GPA = GPA;
  }

  Return true;
}

void LoadDataBase()
{
  //open file 
  //check open file here
  
  //pass address of array element
  while(read_a_record(   &(StudentRec_array[i])   ))
     i++;

  // close file here
}

int main()
{
  LoadDatabase();
  
  // print name in first element.
  cout << StudentRec_array[0].Name;

  return 0;
}
Last edited on
Thanks for the help Jikax!

Since that portion of code is now working, I have another question about the next portion of my code.

I am trying to create a menu for the user to choose from and the first option is to add another Student Record to the array, so I have come up with this code so far....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
    LoadDatabase();

    int choice;

    cout<<"\n\n Please choose one of the menu options:\n\n";
    cout<<"  (1) Add a Student Record\n";
    cout<<"  (2) Delete a Student Record\n";
    cout<<"  (3) Find a student's information\n";
    cout<<"  (4) Display entire database\n";
    cout<<"  (5) Exit the Program\n";

    cin>>choice;

    if(choice == 1)
    {
        Insert_Record();
    }


Here is the function :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Insert_Record()
{
    st_rec.open ("StudentRecord.txt");
    
    if(st_rec.is_open())
    {
        string Name_insert;
        string ID_insert;
        string GPA_insert;
        cout<<"\nWhat is the student's full name? ";
        getline(cin,Name_insert);
        cout<<"\nWhat is the student's ID? ";
        getline(cin,ID_insert);
        cout<<"\nWhat is the student's GPA?";
        getline(cin,GPA_insert);
    }
    else
    {
        cout<<"file could not be opened.";
    }
    
}


However, my getline()'s are causing me problems. When they are displayed on the prompt, the first one is skipped and then the display appears off by one. For instance, the prompt says "what is the student's full name? but gives the user no time to input the name, and jumps straight to "what is the student's ID?"

I have also not yet figured out how to add a value to the end of the array, I think I need to declare an int that tracks the end of the array then add the data input by the user onto the end of the array. Is this the right direction?
When you create an array, it needs to be a constant integer. You should look up vectors, this would suit you much more than an array.
http://www.cplusplus.com/reference/stl/vector/push_back/

As for the above code, why do you open a file and then ask the user for input( cin )?
indeed, add a index.

and why not use cin like you did before?


cin >> Name_insert;

And you create new elements, why not use the already available element inside the array?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if(index < ARRAY_SIZE)
{
        cout<<"\nWhat is the student's full name? ";
        cin >> StudentRec_array[index].Name;

        cout<<"\nWhat is the student's ID? ";
         cin >> StudentRec_array[index].Name;

        cout<<"\nWhat is the student's GPA?";
         cin >> StudentRec_array[index].GPA;

       //increase index
       index++;
}


I guess you want to add the data to the file, but you are using ifstream. Which is a INPUT file stream.
Thanks for the help guys.

Here is my code so far. I only have a couple things left that are stumping me.
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <string>
#include <sstream>

using namespace std;

ifstream st_rec;
int track_array=0;


struct StudentRec
{
    string Name;
    string ID;
    double GPA;
};

const int ARRAY_SIZE =100;
StudentRec StudentRec_array[ARRAY_SIZE];

 bool read_a_record (StudentRec& srec)
{
    string fName,lName;
    string vID;
    double vGPA;

    if(st_rec.is_open())
    {
        bool recordWasRead = st_rec>>fName>>lName>>vID>>vGPA;
        if(! recordWasRead)
        {
            return false;
        }

        srec.Name=lName+","+fName;
        srec.ID=vID;
        srec.GPA=vGPA;
        return true;
    }

    else
    {
        cout<<"file could not be opened.";
        return false;
    }
}

void LoadDatabase()
{
    st_rec.open ("StudentRecord.txt");
    int i=0;

    if(st_rec.is_open())
    {
        while(read_a_record(StudentRec_array[i]))
        {
        i++;
        track_array++;
        }
    }
    else
        cout<<"Unable to open file.";
    st_rec.close();

}

void Insert_Record(StudentRec& srec)
{
    st_rec.open ("StudentRecord.txt");

    if(st_rec.is_open())
    {
        string Name_insert;
        string ID_insert;
        double GPA_insert;
        cout<<"\nWhat is the student's full name? ";
        getline(cin,Name_insert);
        getline(cin,Name_insert);
        cout<<"\nWhat is the student's ID? ";
        getline(cin,ID_insert);
        cout<<"\nWhat is the student's GPA? ";
        cin>>GPA_insert;

        if (track_array<ARRAY_SIZE)
        {
            srec.Name=Name_insert;
            srec.ID=ID_insert;
            srec.GPA=GPA_insert;
            track_array++;
        }
        else
            cout<<"Cannot accept entries larger than the array size.";

    }
    else
    {
        cout<<"file could not be opened.";
    }

}

void Delete_Record()
{

}

void Find_Record()
{
    int i;
    string ID_Search;
    cout<<"Please enter the ID of the student you wish to find information about.\n";
    getline(cin,ID_Search);
    getline(cin,ID_Search);

    for(i=0;i<ARRAY_SIZE;i++)
    {
        if(StudentRec_array[i].ID==ID_Search)
        {
            cout<<"The student has been found.\n";
            cout<<"Name: "<<StudentRec_array[i].Name<<"\n";
            cout<<"ID: "<<StudentRec_array[i].ID<<"\n";
            cout<<"GPA: "<<StudentRec_array[i].GPA<<"\n";
        }
    }

}

bool Print_Records(StudentRec srec)
{
    cout<<srec.Name<<"\t\t";
    cout<<srec.ID<<"\t\t";
    cout<<srec.GPA<<endl;
}

int main()
{
    LoadDatabase();
    bool response;
    int choice;

    do
    {
        cout<<"\n\n Please choose one of the menu options:\n\n";
        cout<<"  (1) Add a Student Record\n";
        cout<<"  (2) Delete a Student Record\n";
        cout<<"  (3) Find a student's information\n";
        cout<<"  (4) Display entire database\n";
        cout<<"  (5) Exit the Program\n";

        cin>>choice;

        if(choice == 1)
        {
            int n=0;
            Insert_Record(StudentRec_array[track_array]);
        }

        else if(choice == 2)
        {
            Delete_Record();
        }

        else if(choice == 3)
        {
            Find_Record();
        }

        else if(choice == 4)
        {
            int rec_num=0;
            int i=0;
            st_rec.open ("StudentRecord.txt");
            while(i<ARRAY_SIZE)
            {
                if(i<ARRAY_SIZE)
                {
                    cout<<++rec_num<<"\t";
                    Print_Records(StudentRec_array[i]);
                }
                else
                    break;
                i++;
            }
        }
        else if (choice == 5)
        {
            cout<<"Ending the Program\n";
        }
        else
        {
            cout<<"You must enter a valid choice between 1 and 5.\n";
            cout<<"Please run the program again.\n\n";
        }

        cout<<"\n\nWould you like to choose another menu option?\n";
        cout<<"Enter 0 for no. Enter 1 for yes.\n";
        cin>>response;
    }
    while(response==1);

    return 0;
}


When the user wants to find a students information, and the function Find_Record() is called, how can I display an error message for when no student ID match is found. I only want the message to display once, not for every i value that does not match.

I have also not yet figured out a way to implement the Delete_Record () function yet. Any tips would be much appreciated.
add a break and check i;

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
void Find_Record()
{
    int i;
    string ID_Search;
    cout<<"Please enter the ID of the student you wish to find information about.\n";
    getline(cin,ID_Search);
    getline(cin,ID_Search);

    for(i=0;i<track_array ;i++)
    {
        if(StudentRec_array[i].ID==ID_Search)
        {
            cout<<"The student has been found.\n";
            cout<<"Name: "<<StudentRec_array[i].Name<<"\n";
            cout<<"ID: "<<StudentRec_array[i].ID<<"\n";
            cout<<"GPA: "<<StudentRec_array[i].GPA<<"\n";

            //found it!
            break;
        }
    }

    if(i == track_array )
    {
            //reached the end of the data
            cout << "Could not find student with id " << ID_Search << endl;
    }

}


compare with track_array, not with ARRAY_SIZE. because the data in elements >= track_array is invalid data.

deleting a item is not that hard.
Just copy the other items over it.
start at the item you want to delete and just move everything.

1
2
3
4
5
6
for(int i = ID_Delete; i < (track_array - 1 ); i++)
{
    StudentRec_array[i] = StudentRec_array[i+1];
}
//decrease index
track_array--;

Last edited on
Thanks again for the help Jikax.

I follow your solution to the Find_Record() function easy to follow, however I am getting caught up on the delete record fuction.

If i is an integer, ID_Delete must be an integer as well, or I will get a type conversion error right?

If that is true, wouldn't that portion of code require me to ask the user to input an integer value?

Also, in the for loop, when you are using i<track_array - 1 for your conditional check, with this statement:

StudentRec_array[i] = StudentRec_array[i+1];

does that mean all of the structures from track_array-1 to the end of the array are moved up 1 spot on the array because of the conditional check?
ID_delete is the id of the element you want to delete, how you get this number is up to you.

(track_array-1) is the last valid value inside the array. all data from ID_Delete to (track_array-1) is being moved up 1 place. overwriting the one you want to delete.

Keep in mind that afterwards the elements StudentRec_array[track_array-1] and StudentRec_array[track_array] are the same. but because only the values < track_array are valid this is not a problem.
Thanks for the explanation Jikax.

I am having another issue now with saving the changes made to the array in the program to the file.

Here is my code so far:

inside the main function:

1
2
3
4
5
        else if (choice == 5)
        {
            SaveDatabase();
            cout<<"Ending the Program\n";
         }


then the function itself:
1
2
3
4
5
6
7
8
9
10
11
void SaveDatabase()
{
    int i=0;
    st_rec.open ("StudentRecord.txt");

    while(st_rec.is_open() && i<track_array)
    {
        st_rec<<StudentRec_array[i]<<"\n";
        i++;
    }
}


I am getting an error saying "no match for operator << in st_rec << studentrec_array[i]"

I am including fstream, and I have changed the ifstream st_rec code to fstream st_rec;

and I know in the boolean function read_a_record this code works:

bool recordWasRead = st_rec>>fName>>lName>>vID>>vGPA;

so I know the st_rec can input data successfully, but for some reason I have yet to figure out, I cannot output the array back to the file.

Any ideas?
You are trying to write a array element to the file.
The element is of type StudentRec, but fstream does not know what he needs to do with a StudentRec element.

you need to write the data inside the element individially:

1
2
3
4
st_rec << StudentRec_array[i].Name 
    << " " << StudentRec_array[i].ID
    << " " << StudentRec_array[i].GPA 
    << "\n";


but since you are using c++, this may be easier:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct StudentRec
{
    string Name;
    string ID;
    double GPA;

    string Serialise(){
       stringstream out;
       out << Name << " " << ID << " " << GPA << "\n";
       return out.str();
    };
};



st_rec << StudentRec_array[i].Serialise();
Last edited on
Thanks for all of the help Jikax.
Topic archived. No new replies allowed.