Write to the end of .csv file

Pages: 123
I'm using Windows 10 and Visual Studio, and I'm intending to use just a 1D array. The code I have done was just read one students list in 5 students list files and one timetable from 5 timetable files.
Maybe this is taking too much energy from me since my eyes usually red just like using cannabis.
Last edited on
Hello thinhphucvang,

I to use Windows and VS, so that is a help.

You could use 1D arrays to do this, but consider that you would have five arrays for the "stucent.csv" type files and five arrays for the "timetable.csv" type files. Then you would need five variables like "index" plus five variables like "tIndex". This would be 20 lines of code for all of this.

With a 2D array this can be shortened to four lines of code.

This is a rough idea of what a 2D array would look like:

r               c c c c     c
o               o o o o     o
w               l l l l     l
-----------------------------
1 student.csv   0 1 2 3 ... 99

2 struent1.csv  0 1 2 3 ... 99

3 student2.csv  0 1 2 3 ... 99

4 struent3.csv  0 1 2 3 ... 99

5 student4.csv  0 1 2 3 ... 99


Each row would be a different file and each roe would have 100 structs. In reality the file name do not appear.

If you know about and can use a "std::vector" it would be a better choice. A vector will only hold what it needs and nothing extra whereas an array will most likely have unused elements just wasting space.

You have started with a program the reads and deals with two files and that is file to understand the basics of what needs to be done.

Now you are saying that you want to read from ten different files and do something with the program to manage this information.

If this is a class project then post the instructions that you were given so I have a better idea what needs to be done. If this is a personal project then a little more direction is needed.

You talk about creating an "account.txt" file. Is there a reason for that? It would be easier to put the IDs in an array of strings. This would work better and be less overhead when the program runs.

Just some thoughts for now. I am still working on the changes.

Hope that helps,

Andy
Here's my class's full project
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
CTT008/CS162 Final project – Student managementsystem
Class: 18APCS1-2-3, 18CLC1-2-3-4-6
Use-cases:
• All roles:
1. Login
2. Show menu
3. View profile info
4. Change password
5. Logout
• Academic staff:
Class:
6. Import students of a class such as 18CLC6 from a csv file.
§ The csv file should include columns such as No (1), Student ID
(18125001), Lastname (Nguyen Van), Firstname (A), Gender (Male), DoB
(2000-04-01).
§ Remember to create student accounts based on their Student ID (the username and password are both the ID).

7. Manually add a new student to a class.
§ For example, there is a new student enrolled in 18CLC6.
§ Remember to create a student account based on his/her Student ID (the username and password are both the ID).
8. Edit an existing student.
9. Remove a student.
10. Change students from class A to class B
11. View list of classes.
12. View list of students in a class.
Courses:
13. Create / update / delete / view academic years (2018-2019), and semesters
(Fall).
14. From a semester, import courses such as CTT008, CTT010 from a csv file.
§ The csv file should include columns such as No (1), Course ID (CTT008),
Course Name (Programming Techniques), Class (18CLC6),
LecturerAccount (nhminh), Start Date (2019-01-07), End Date (2019-04-
13), Day of Week (Wed), Start Hour:Minute (08:00), and End
Hour:Minute (11:00), Room (I33).
§ By default, all students in the mentioned classes will be enrolled to
imported courses.
15. Manually add a new course.
16. Edit an existing course.
17. Remove a course.
18. Remove a specific student from a course.

§ For example, by default all students of 18CLC are enrolled in course
CTT008, but because of a private reason, student Nguyen Van A is
dropped from CTT008.
19. Add a specific student to a course.
§ For example, student 1753001 enrolls in CTT008 to improve his previous
result.

20. View list of courses in the current semester.
21. View list of students of a course.
22. View attendance list of a course.
23. Create / update / delete / view all lecturers.
Scoreboard:
24. Search and view scoreboard of a course.
25. Export a scoreboard to a csv file.
Attendance list:
26. Search and view attendance list of a course.
27. Export a attendance list to a csv file.
• Lecturer:
28. View list of courses in the current semester.
29. View list of students of a course.
30. View attendance list of a course.
31. Edit an attendance.
32. Import scoreboard of a course (midterm, final, lab, bonus) from a csv file.
33. Edit grade of a student
34. View a scoreboard
• Student:
35. Check-in.
36. View check-in result.
37. View schedules.
38. View his/her scores of a course.

Requirements
• Menu
• Data must be stored in file. You can define your own format but it must store all the
information as describe above. Be sure that, if I delete a csv file after importing, there is
no harm to your system.
• Hash password (optional). Tip: SHA1, SHA256...

I think that creating a file name account.txt will be easier for me to edit the password, since the task 4 at the beginning is "change password". My lecturer also asked to write each list of students into another .txt file, that is what we disscussed days before. But I think this is just consuming more time rather than making the program looks nicer.
Last edited on
main:
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include "func.h"

int main()
{
	size_t index{}, tIndex{};
	ifstream in;
	in.open("E:/students.csv");
	Student student[100];
	string  No, student_id, Last_name, First_name, Gender, DoB;
	// Read the student.csv
	if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No, ',');
		getline(in, student_id, ',');
		getline(in, Last_name, ',');
		getline(in, First_name, ',');
		getline(in, Gender, ',');
		getline(in, DoB, '\n');
		while (getline(in, student[index].no, ','))
		{
			getline(in, student[index].id, ',');
			getline(in, student[index].last_name, ',');
			getline(in, student[index].first_name, ',');
			getline(in, student[index].gender, ',');
			getline(in, student[index++].dob, '\n');
		}
		in.close();
	}
	// Write the password and username into acc.txt
	ofstream out, outacc;
	outacc.open("E:/acc.txt");
	if (!outacc.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		outacc << "No User Pass\n";
		for (int i = 0; i < index; i++)
		{
			outacc << student[i].no << " " << student[i].id << " " << student[i].id << endl;
		}
		outacc.close();
	}
	// Write the readed content from the .csv into a .txt 
	out.open("E:/student.txt");
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << No << "," << student_id << "," << Last_name << "," << First_name << "," << Gender << "," << DoB << endl;
		for (int i = 0; i < index; i++)
		{
			out << student[i].no << " ";
			out << student[i].id << " ";
			out << student[i].last_name << " ";
			out << student[i].first_name << " ";
			out << student[i].gender << " ";
			out << student[i].dob << endl;
		}
		out.close();
	}

	//Read the timetable.csv
	Timetable t[100];
	string No_t, Course_ID, LectureAccount, Class, LecturesAccount, Start_Date, End_Date, Day_of_week, Start_hour, End_hour, Room;
	in.open("E:/timetable.csv");
	if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No_t, ',');
		getline(in, Course_ID, ',');
		getline(in, LectureAccount, ',');
		getline(in, Start_Date, ',');
		getline(in, End_Date, ',');
		getline(in, Day_of_week, ',');
		getline(in, Start_hour, ',');
		getline(in, End_hour, ',');
		getline(in, Room, '\n');
		while (getline(in, t[tIndex].courses_no, ','))
		{
			getline(in, t[tIndex].courses_no, ',');
			getline(in, t[tIndex].courses_id, ',');
			getline(in, t[tIndex].lecture_account, ',');
			getline(in, t[tIndex].start, ',');
			getline(in, t[tIndex].end, ',');
			getline(in, t[tIndex].day, ',');
			getline(in, t[tIndex].start_hour, ',');
			getline(in, t[tIndex].end_hour, ',');
			getline(in, t[tIndex++].room, '\n');
		}
		in.close();
	}
	// Write the readed content from the .csv into a .txt 
	out.open("E:/timetable.txt");
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << No_t << " " << Course_ID << " " << LectureAccount << " " << Start_Date << " " << End_Date << " " << Day_of_week << " " << Start_hour << " " << End_hour << " " << Room << endl;
		for (int i = 0; i < tIndex; i++)
		{
			out << t[i].courses_no << " " << t[i].courses_id << " " << t[i].lecture_account << " " << t[i].start << " " << t[i].end << " " << t[i].day << " " << t[i].start_hour << " " << t[i].end_hour << " " << t[i].room << endl;
		}
		out.close();
	}

	//username, pass
	ifstream inpass;
	inpass.open("E:/acc.txt");
	Pass p[100];
	string No_p, User, Pass;
	getline(inpass, No_p, ' ');
	getline(inpass, User, ' ');
	getline(inpass, Pass, ' ');
	if (!inpass)
	{
		cout << "Error!\n";
	}
	else
	{
		for (int i = 0; i < index; i++)
		{
			getline(inpass, p[i].no, ' ');
			getline(inpass, p[i].user, ' ');
			getline(inpass, p[i].pass, '\n');
		}
		inpass.close();
	}

	cout << "1.Login\n";
	cout << "2.Exit\n";
	int  a;
	cin >> a;
	system("cls");
	if (a == 1)
	{
		string user, pass;
		cout << "1.Username: ";
		cin >> user;
		cout << "2.Pass: ";
		cin >> pass;
		for (int i = 0; i < index; i++)
		{
			if (user == p[i].user && pass == p[i].pass)
			{
				int c;
				system("cls");
				cout << "1. Staff menu\n";
				cout << "2. Lecturer menu\n";
				cout << "3. Student menu\n";
				cin >> c;
				switch (c)
				{
				case 1:
					system("cls");
					cout << "1. Class\n" << "2. Courses\n" << "3. Scoreboard\n" << "4. Attendance list\n" << "5. Change pass\n";
					cin >> c;
					switch (c)
					{
					case 1:
						system("cls");
						cout << "1. Add student\n" << "2. Edit student's info\n" << "3. Remove student\n";
						cout << "4. Change student\n" << "5. View classes's list\n" << "6. View list of a class's students\n";
						int d;
						cin >> d;
						switch (d)
						{
						case 1:
							system("cls");
							AddStu(student, index);
							break;
						case 2:
							system("cls");
							EditStu(student, index);
							break;
						case 3:
							system("cls");
							// NOT DONE
							break;
						case 4:
							system("cls");
							// NOT DONE
							break;
						case 5:
							system("cls");
							// NOT DONE
							break;
						case 6:

							cout << No << "  " << student_id << "   " << Last_name << "     " << First_name << "  " << Gender << "    " << DoB << endl;
							for (int i = 0; i < index; i++)
							{
								cout << right << setw(2) << student[i].no << "   ";
								cout << left << setw(10) << student[i].id << "  ";
								cout << setw(12) << student[i].last_name << "  ";
								cout << setw(11) << student[i].first_name << " ";
								cout << setw(6) << student[i].gender << "  ";
								cout << student[i].dob << endl;
							}
						}
					}

				case 2:
					system("cls");
					// not done
					break;
				case 3:
					system("cls");
					// not done
					break;
				default:
					system("cls");
					break;
				}
			}
			else
			{
				system("cls");
				cout << "Wrong password! try again!\n";
				return main();
			}
		}
	}
	else
	{
		return 0;
	}

	system("pause");
}
header:
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
#ifndef _FUNC_H_
#define _FUNC_H_

#include <iostream>
#include <fstream>
#include <limits>
#include <string>
#include <iomanip>

#define MAX_STUDENT 100
#define MAX_COURSE 100

using namespace std;


struct Student
{
	string no, id, last_name, first_name, gender, dob;
};
struct Timetable
{
	string courses_no, courses_id, lecture_account, class_name, lectures_account, start, end, day, start_hour, end_hour, room;
};

struct Pass
{
	string no, user, pass;
};
struct listStudent
{
	char class_name[20];
	int num_student;
	Student students[MAX_STUDENT];
};

struct Class
{
	listStudent list_student[5];
};
struct listCourse
{
	char class_courses[20];
	Timetable courses[MAX_COURSE];
	int num_coures;
};
struct allCourses
{
	listCourse list_courses[5];

};

void AddStu(Student student[], int index);
void EditStu(Student student[], int index);
// void changePass(Pass p[], int index);

#endif 
function:
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
#include "func.h"

void AddStu(Student student[], int index)
{
	ofstream out;
	string newLastName, newFirstName, newID, newGender, newDob;
	cout << "Enter new ID: ";
	cin >> newID;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter new first name: ";
	getline(cin, newFirstName);
	cout << "Enter new last name: ";
	getline(cin, newLastName);
	cout << "Enter new gender: ";
	cin >> newGender;
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	cout << "Enter dob: ";
	getline(cin, newDob);

	student[index + 1].id = newID;
	student[index + 1].first_name = newFirstName;
	student[index + 1].last_name = newLastName;
	student[index + 1].gender = newGender;
	student[index + 1].dob = newDob;
	out.open("E:/students.csv", std::ios::app);
	if (!out.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		out << index + 1 << "," << student[index + 1].id << "," << student[index + 1].first_name << "," << student[index + 1].last_name << "," << student[index + 1].gender << "," << student[index + 1].dob << endl;
		out.close();
	}
}
void EditStu(Student student[], int index)
{
	string stuid, ID, Last_name, First_name, Gender, Dob;
	cout << "Enter the student's ID you want to change: ";
	cin >> stuid;
	ofstream out;
	out.open("E:/students.csv", std::ofstream::trunc);
	if (!out)
	{
		cout << "Error!\n";
	}
	else
	{
		for (int i = 0; i < index; i++)
		{
			if (student[i].id == stuid)
			{
				cout << "1. Change ID\n" << "2. Change last name\n" << "3. Change first name\n" << "4. Change gender\n" << "5. Change DoB\n";
				int e;
				cin >> e;
				switch (e)
				{
				case 1:
					cout << "New ID: ";
					cin >> ID;
					student[i].id = ID;
					break;
				case 2:
					cout << "New last name: ";
					cin >> Last_name;
					student[i].last_name = Last_name;
					break;
				case 3:
					cout << "New first name: ";
					cin >> First_name;
					student[i].first_name = First_name;
					break;
				case 4:
					cout << "New gender: ";
					cin >> Gender;
					student[i].gender = Gender;
					break;
				case 5:
					cout << "New dob: ";
					cin >> Dob;
					student[i].dob = Dob;
					break;
				}

			}
		}
		out << "No,Student ID,Lastname,Firstname,Gender,DoB\n";
		for (int i = 0; i < index; i++)
		{
			out << student[i].no << ",";
			out << student[i].id << ",";
			out << student[i].last_name << ",";
			out << student[i].first_name << ",";
			out << student[i].gender << ",";
			out << student[i].dob << endl;
		}
		out.close();
	}
}

/*void changePass(Pass p[], int index)
{
	ofstream out;
	out.open("E:/acc.txt");
	if (!out)
	{
		cout << "Error!\n";
	}
	else
	{
		string newpass, no, user, pass;
		cout << "Enter your user: ";
		cin >> user;
		cout << "Enter old password: ";
		cin >> pass;
		for (int i = 0; i < index; i++)
		{
			if (user == p[i].user && pass == p[i].pass)
			{
				NOT DONE
			}
		}
	}
	out.close();
}*/
students.csv:
1
2
3
4
5
6
7
8
9
10
11
No,Student ID,Lastname,Firstname,Gender,DoB
1,1653054,Pham Huu,Nghia,Male,2000-06-01
2,188888888,Truong Minh,Thien,Male,2000-08-03
3,1753017,Nguyen Huu,Tuan,Male,2000-04-03
4,1753097,Le Nguyen Minh,Tam,,2000-07-05
5,1753099,John,Tan,Male,2000-04-05
6,1753103,Ngo Viet,Thang,Male,2000-04-06
7,1753120,Pham Huu,Tuan,Male,2000-04-07
8,1753128,Le Quoc,Viet,Male,2000-04-08
9,1753129,Nguyen Hoang,Viet,Male,2000-04-07
10,1753131,Nguyen Vuong Dat ,Vu,Male,2000-04-10

timetable.csv:
1
2
3
4
5
6
7
8
9
No,Course ID,LectureAccount,Class,LecturesAccount,Start Date,End Date,Day of week,Start hour:Minute,End hour:Minute,Room
1,CTT008,Ky thuat lap trinh,18CLC2,nmhuy,2019-01-07,2019-04-13,tues,13:30,15:10,B.40
2,CTT008-TH,Ky thuat lap trinh thuc hanh,18CLC2,htthanh,2019-01-07,2019-04-13,thur,7:30,9:30,I.61
3,CTT010,Nhap mon cong nghe thong tin 2,18CLC2,vhviet,2019-01-07,2019-04-13,wed,7:30,11:10,I.23
4,CTT010-TH,Nhap mon cong nghe thong tin 2 thuc hanh,18CLC2,pmhoang,2019-01-07,2019-04-13,mon,15:30,17:30,C.23A
5,CTH026,Giai tich B1,18CLC2,nttvan,2019-01-07,2019-04-13,sat,7:30,11:10,I.42
6,CTT026-TH,Giai tich B1-TH,18CLC2,nthnhung,2019-01-07,2019-04-13,wed,13:30,15:30,I.71
7,KTH001,Kinh te dai cuong,18CLC2,pxkien,2019-01-07,2019-04-13,fri,7:30,11:10,I.41
8,CTH001,Nhung nguyen li co ban cua CN mac le nin,18CLC2,nqhuy,2019-01-07,2019-04-13,mon,7:30,11:10,B.11A

acc.txt:
1
2
3
4
5
6
7
8
9
10
11
No User Pass
1 1653054 1653054
2 188888888 188888888
3 1753017 1753017
4 1753097 1753097
5 1753099 1753099
6 1753103 1753103
7 1753120 1753120
8 1753128 1753128
9 1753129 1753129
10 1753131 1753131

I'm a fresh man in college and I'm working in this project with 3 other guys. I'm not the leader but I do more than them since my English is better. They said creating another struct containing a 6 elements to read and store the 5 different files. I was intended to use vectors but my teacher hasn't taught and my team no little about it (I used to learn C++ by myself when I'm 16 so I know what a vector is). And I don't want to make them confuse about coding this project so I use arrays.
Is it a good way to store all 5 files in an 5-element array?
Hello thinhphucvang,

Thank you for the instructions. That helps very much.

One of the first things I see that could cause problems in in the "func.h" file.

The use of the header guard is good.

These lines of code:
1
2
3
4
5
6
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>

#include <fstream> 

Should not be in the header file ""func.h". they are better put in the ".cpp" files.
Putting these header files in the "func.h" header file may seem like an easy way for now, but in the future, if you get use to this, will be a problem and harder to track down because error messages will tell you where the problem is not where it started.

The blank line helps show that everything above it are the header files most common to a program and what is below is the extras that you would need.

The "#define" statements work, but do not get use to them as they are not the best way to do what you want. constexpt size_t MAX_STUDENT{ 100 }; or const size_t MAX_STUDENT{ 100 }; is much better.

The line using namespace std; should never be put in a header file. There have been many posts here about this. Do a search and read some of them. Also this is worth reading: http://www.lonecpluspluscoder.com/2012/09/22/i-dont-want-to-see-another-using-namespace-xxx-in-a-header-file-ever-again/

Its bad enough that you have been told to use using namespace std; now because, as I believe that some people think it is to early to teach you the correct way, and they leave it to later for those students that really want to become programmers.

Everything else is good until the struct "listStudent". Why the char array and not a std::string? And the same question for "listCourse".

In the "main" file you have the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (!in.is_open())
	{
		cout << "Error!\n";
	}
	else
	{
		getline(in, No, ',');
		getline(in, student_id, ',');
		getline(in, Last_name, ',');
		getline(in, First_name, ',');
		getline(in, Gender, ',');
		getline(in, DoB, '\n');
		while (getline(in, student[index].no, ','))
		{
			getline(in, student[index].id, ',');
			getline(in, student[index].last_name, ',');
			getline(in, student[index].first_name, ',');
			getline(in, student[index].gender, ',');
			getline(in, student[index++].dob, '\n');
		}
		in.close();
	}


As I have shown you it should be like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	if (!in)
	{
		std::cout << "\n File \"" << "E:/students.csv" << "\" did not open" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread".
		return 1;  //exit(1);  // If not in "main".
	}

	getline(in, No, ',');
	getline(in, student_id, ',');
	getline(in, Last_name, ',');
	getline(in, First_name, ',');
	getline(in, Gender, ',');
	getline(in, DoB, '\n');

	while (getline(in, student[index].no, ','))
	{
		getline(in, student[index].id, ',');
		getline(in, student[index].last_name, ',');
		getline(in, student[index].first_name, ',');
		getline(in, student[index].gender, ',');
		getline(in, student[index++].dob, '\n');
	}

Even better is when you put "E:/students.csv" into a string variable an use it.

Looking at the if statement the first line is the error message. the second line is optional. The way my VS is setup the console window running the program closes when the program ends making it hard to see any last message sent to the screen. You may or may not need this. The nice part of C++ is that you do not always have to understand a piece of code just know to use it. Later on, in a more advanced class, you will learn about "chrono" and "thread" and understand better what this does. For not all you need to know is the "3". This is the number of whole seconds this line of code will pause or wait before the program continues. Changing the "3" to a different whole number will lengthen or shorten the amount of time it pauses.

The last line will leave the program because there is no point in continuing. If the file stream did not open properly this needs to be fixed before the program can continue.

Consider the logic of the if/else statement:
1
2
3
if (!in)

else

To start with you should take a look at this: http://www.cplusplus.com/reference/ios/ios/good/ At first I want you to look at the table. The table that has "iostate value (member constant)" on the left.

"!in" if the file stream opened properly the "good" bit is set to "1" making it true and not (!) changes it to false to bypass the the if block and go to the else block. Should the stream fail in the open the "good" bit is set to "0" making it false and not (!) changes it to true entering the if block and bypassing the else block. The problem with this is that the program can continue never reading the file and you will not know about the problem until you try to process information that is not there and wondering what happened.

As I am showing you by exiting the program in the if statement it means you need to fix the problem before you can continue. Having the if/else the way you do is working against you and not helping.

And the same applies to all the other file streams.

Looking at what you have in "main" and the way you have started I see a potential of 1000 lines of code or more to do what you need. This program needs function to do the repetitive work.

Yesterday, while thinking about the multi file problem, I created a function to just open files and one to read those files. They have potential, but difficult to work with in a for loop.

I do need to understand more about how the "main" function is working first.

Rather than explain everything I will give you this:
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
#include <iostream>
#include <chrono>
#include <thread>

int MainMenu()
{
	int choice{};

	do
	{
		system("cls");

		std::cout
			<< "\n 1. Login"
			<< "\n 2. Show menu"
			<< "\n 3. View profile info"
			<< "\n 4. Change password"
			<< "\n 5. Logout"
			<< "\n  Enter choice: ";
		std::cin >> choice;

		if (choice < 1 || choice > 5)
		{
			std::cout << "\n  Invalid Choice! Try again" << std::endl;
			std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread".
		}

	} while (choice < 1 || choice > 5);

	return choice;
}

I am use to doing this in its own file. You could skip the "#includes" and put this with the other functions. I called the file "func.cpp" for now.

What this function does is only return a valid choice that can be used eliminating the need to check it later.

In "main" you will need:
1
2
3
int menuChoice{};
	
menuChoice = MainMenu();

You can change the variable name if you want.

Hope that helps,

Andy
Hello thinhphucvang,

It slipped by me in your last response.

Is it a good way to store all 5 files in an 5-element array?

I think what you mean is five file names in an array.

The answer is yes.

This is something I was thinking about yesterday:
const std::string inFileNames[]{ "students.csv", "students2.csv", "File3.csv", "File4.csv", "File5.csv", "timetable.csv" };
Looking at it now I would change the variable name and put "timetable.csv" in its own string since it is a different type of file.

Making the variable a constant means that you can not accidentally change any of the file names in the program.

Hope that helps,

Andy
I'm I getting this right:
The program should try its best to read the file rather than exiting if the file is fail to read.
By using goodbit() and failbit(), I can find out where the file have something wrong and fix it.
Is it right?
I haven't heared about this type of value until today
Yes, my meaning is 5 files name in an array.
Now to read those files, I have to write a function to read the file, using a for loop with int i = 0; i < 5; i++ to call that function in order read each files respectively.
Correct?
Hello thinhphucvang,

This is what I have done 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
68
69
70
#include <iostream>
#include <iomanip>
#include <string>

#include <fstream>
#include <limits>
#include <chrono>
#include <thread>

#include "func.h"
#include "Proto.hpp"

using namespace std;


int main()
{
	//menuChoice = MainMenu();  // <--- Move later.
	//return 0;  // <--- Used for testing.

	//const std::string PATH{ "E:/" };  // <--- Just an example of what you  could do.
	const std::string inFileNames[]{ "students 1.csv", "students 2.csv", "students 3.csv", "students 4.csv", "students 5.csv" };
	//const std::string InFileNames[]{ PATH + "students.csv", PATH + "File2", PATH + "File3", PATH + "File4" };

	bool haveHeadings{};
	size_t index1{}, index2{}, index3{}, index4{}, index5{}, tIndex{};
	int menuChoice{};
	
	Student student1[MAXSTUDENT];
	Student student2[MAXSTUDENT];
	Student student3[MAXSTUDENT];
	Student student4[MAXSTUDENT];
	Student student5[MAXSTUDENT];
	string  headings[6];

	ifstream in;

	for (size_t lc = 0; lc < inFileNames->size(); lc++)
	{
		OpenFile(in, inFileNames[lc]);

		switch (lc)
		{
			case 0:
				ReadFile(in, student1, headings, index1, haveHeadings);
				break;
			case 1:
				ReadFile(in, student2, headings, index2, haveHeadings);
				break;
			case 2:
				ReadFile(in, student3, headings, index3, haveHeadings);
				break;
			case 3:
				ReadFile(in, student4, headings, index4, haveHeadings);
				break;
			case 4:
				ReadFile(in, student5, headings, index5, haveHeadings);
				break;
		}
	}

	// <--- Used mostly for testing in Debug mode. Removed if compiled for release.
	// <--- Used to keep the console window open in Visual Studio Debug mode.
	// The next line may not be needid. If you have to press enter to see the prompt it is not needed.
	//std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "\n\n Press Enter to continue: ";
	std::cin.get();

	return 0;
}

Lines 21 and 23 are examples of something you could do. Sometimes it is easier to define the variable "PATH" and use it than to put the path in each file name. Also if thepath changes you only have to change it in one place.

In the for loop the "OpenFile()" function call works fine this way. I used the switch because each call to "ReadFile() needs different variables sent. You can not do this with a normal for loop.

Lines 62 to 67 are what I use in place of "system("pause");" I would suggest some or all of these lines in place of the "system" call.

"func.h":
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
#ifndef _FUNC_H_
#define _FUNC_H_

#define MAX_STUDENT 100
#define MAX_COURSE 100

constexpr size_t MAXHEADINGS{ 6 };
constexpr size_t MAXSTUDENT{ 50 };
constexpr size_t MAXCOURSE{ 50 };

struct Student
{
	std::string no, id, last_name, first_name, gender, dob;
};
struct Timetable
{
	std::string courses_no, courses_id, lecture_account, class_name, lectures_account, start, end, day, start_hour, end_hour, room;
};

struct Pass
{
	std::string no, user, pass;
};
struct listStudent
{
	char class_name[20];
	int num_student;
	Student students[MAX_STUDENT];
};

struct Class
{
	listStudent list_student[5];
};
struct listCourse
{
	char class_courses[20];
	Timetable courses[MAX_COURSE];
	int num_coures;
};

struct allCourses
{
	listCourse list_courses[5];

};

// void changePass(Pass p[], int index);

#endif 

The "#define"s work, but they are not the best way to use them. Whether you use "constextr" or "const" either is the better way to do this. Right now both ways are there and both work.

Added to what I called "func.cpp":
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
void OpenFile(std::ifstream& inFile, std::string inFileName)
{
	inFile.open(inFileName);

	if (!inFile)
	{
		std::cout << "\n  Error! file \"" << inFileName << "\" did not open." << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(5));  // Requires header files "chrono" and "thread". Optional.
		/*return 1;*/  exit(1);  // If not in "main".
	}
}

void ReadFile(std::ifstream& inFile, Student(&student)[MAXSTUDENT], std::string(&headings)[MAXHEADINGS], size_t& index, bool& haveHeadings)
{
	std::string junk;

	if (!haveHeadings)
	{
		std::getline(inFile, headings[0], ',');
		std::getline(inFile, headings[1], ',');
		std::getline(inFile, headings[2], ',');
		std::getline(inFile, headings[3], ',');
		std::getline(inFile, headings[4], ',');
		std::getline(inFile, headings[5], '\n');

		haveHeadings = true;
	}
	else
		std::getline(inFile, junk);

	while (!(inFile.eof()) && std::getline(inFile, student[index].no, ','))
	{
		std::getline(inFile, student[index].id, ',');
		std::getline(inFile, student[index].last_name, ',');
		std::getline(inFile, student[index].first_name, ',');
		std::getline(inFile, student[index].gender, ',');
		std::getline(inFile, student[index++].dob, '\n');

		std::cout << std::endl;  // <--- Used for testing. Good place for a break point.
	}

	inFile.close();
}

The "openFile" functions works for all five files. The "ReadFile" function works for the first four files, but for some reason the while loop will not deal with the (end of file) properly. It tries to read and process past (EOF) resulting in a run time error. Before this it did read and store all the information into the "student5" array properly. This still has me challenged as to what it is doing and why it is nor working.

Files "student 2.csv" - "student 5.csv" are copies of "student 1.csv". The only difference should be the file name.

Even when I looked at the files "student 1" and "student 5" in a program that shows the hex code of everything I could not see any difference between the files.

Maybe someone else would have an idea?

This is a start until I can figure out why the fifth file is not working.

Hope that helps,

Andy
Okay, big assignment, multiple students, how are you breaking this big assignment down to manageable parts?

Have you done anything like flow charts, Pseudocode, etc when designing your program? For a program of this size with multiple people working on it you really need to do some kind of design before you even start working on the actual code. What is the time line allowed for this assignment and the due date?

You really, really need to be using more functions and probably several classes to help streamline the program. By the way what about the other .csv files you will need, I see at least 5 separate files and maybe a couple of others still hidden away in that text.

Also since every .csv file is different you will probably want to have individual classes to hold the information stored in these files. Each class should be able to read the file and store the information inside the class structure.

Also I recommend using std::vector instead of any arrays.

Edit: You should also consider using stringstreams for parsing each individual line of each file. Using a stringstream helps keeping the underlying stream in a "good" state making reading easier and spotting data errors easier.

Last edited on
Hello thinhphucvang,

I finally figured it out.

In "main" the for loop is for (size_t lc = 0; lc < inFileNames->size(); lc++) the "->" should have been my first clue that something was wrong. I was thing that "->" was because the array was defined as a constant, now I am not sure. It turns out that inFileNames->size() is returning the size of the first element and not how many elements are in the array.

I solved the problem by putting constexpr size_t MAXFILES{ 5 }; in the "func.h" file and changing the for loop to for (size_t lc = 0; lc < MAXFILES; lc++) which in this case it is a better way to do this.

Now the for loop is not trying to go past the five defined file names in "inFileNames[]" it works.

I realized earlier that I missed one file:

"proto.hpp"
1
2
3
4
5
6
7
8
9
10
#ifndef _PROTOHPP
#define _PROTOHPP

int MainMenu();
void AddStu(Student student[], int index);
void EditStu(Student student[], int index);
void OpenFile(std::ifstream& inFile, std::string inFileName);
void ReadFile(std::ifstream& inFile, Student(&student)[MAXSTUDENT], std::string(&headings)[MAXHEADINGS], size_t& index, bool& haveHeadings);

#endif // !_PROTOHPP 

Years ago when I was learning C I came up with the idea of "proto.h" for the prototypes of all the functions. This way you have only one place to change or add a new prototype. Then you only have to change the function definition(s) for what you changed.

After a while I decided to make the extension ".hpp" to go along with the ".cpp" extension of C++. The ".h" extension tends to mean that it is a C header file.

Now that everything is working correctly the for loop in "main" can be duplicated to read all the "timetable" files. You will also have to duplicate the "ReadFile", I think I would change "ReadFile" to "ReadStudents" and call the next function "ReadTimeTable" or at least something to make the function names different, and then in "ReadTimeTable" you will need to make the changes for the different file format.

Since there is only one password file that should be easy enough to read.

After that it is time to go back to the instructions for a check of what has been done and what is next.

Hope that helps,

Andy
I got my legs hurt so I haven't moved much, I'm lying on my hammock now and I get moving out hardly.
The deadline of this assignment is in a month, meaning this day on April.
I was wondering:
 
bool& haveHeadings;

Is this for checking the top line of the file? Why does it necessary to do a check for the heading?
Looks like I have to do some fixing a lot more than I think.
There are many concepts that are new to me, such as constextr. I did a Google searching and they said this is a " constant expressions", and "can be used with both member and non-member functions". What is a non-member in this case?
Also:
1
2
Student(&student)[MAXSTUDENT]; 
std::string(&headings)[MAXHEADINGS];

Is the & means reference? I thought this is use only for working with pointers?
Thank you.
Hello thinhphucvang,

Sorry to hear about your legs. I understand what that is like.


I was wondering:

bool& haveHeadings;


When you look at your input file:

No,Student ID,Last name,First name,Gender,DoB
1,18127221,Nguyen Van,Tuan,Male,04/11/2000
2,18127222,Tran Van,A,Female,09/06/2000


The first line is headings. I assume that the other four files are the same. Since each file starts with a line of headings that are all the same there is no reason to read the second and other files and process this line into variables that already have the same values. Using the bool variable is a way to process the headings once and bypass the other files by reading the whole line and not using it.

constexpr is the updated version of const available from C++11 on. Since I missed everything from the start of C++ and all the new standards that came out before C++11 that learning and usung the C++11 standards is a good place to start. That is why I try to use constexpr in stead of const. So far I have figured out that constexpr works well with numeric variables, but not "strings". With "strings" I still have to use const,

In the
1
2
3
4
void ReadFile(std::ifstream& inFile,
Student(&student)[MAXSTUDENT],
std::string(&headings)[MAXHEADINGS],
size_t& index, bool& haveHeadings)

If line 2 was passed by value Student student[], this would degrade to a pointer. This makes no difference in how you write the code in the function. Using student[5], for example, still returns what is stored at the fifth element of the array. When you write student[5] the compiler will change it into what the program needs to access the proper element of the array. I believe this is an offset of the starting address of the array which is based on the size of the type that the array was defined as.

Passing the array by reference allows you so see the entire array not just the first element. In VS if you put a break point in the function and place the cursor over "student", if passed by value you only see the first element of the array, Passing by reference allows you to see all the elements of the array. Quite often I will pass by an array by reference to watch what is happening with the array.

Sometimes I forget to change it back to pass by value when I am done, but you can say that you have learned something new.

I am do not know what you have read, but I would say that "member" would refer to a class member function and "non member" would refer to a regular function.

Yes the "&" in a function definition does mean pass by reference. For a normal variable it would look like int& varName or int &varName either way works. Personally I prefer the first version. And no it is not just for pointers.

In "main" when you define the variables
1
2
bool haveHeadings{};
size_t index1{}, index2{}, index3{}, index4{}, index5{}, tIndex{};
And then pass these variables to a function, pass by value means that you are making a copy and working with it. The problem is that if you change the value of the copy in the function it is lost when the function ends unless you return it value. The draw back to this is that a function can only return one item. Passing by reference eliminates this problem by using the variable defined in "main" and not a copy of it. And sometimes passing a variable by reference saves on the overhead of having to make a copy of something that is large.

Another advantage to pass by reference is that more than one variable can be changed in a function without having to figure out a way to return more than one variable.

And last a pointer only holds an address to something. There is no real need to pass a pointer by reference unless you intend to change its value to point to something else, usually that is not a good idea.

You have some fixing to do, but it is not that hard to work out.

Earlier I said that the "readFile" function should be called "readStudents". This way all you have to do is copy the "readStudents" function and change the function name to "readTimeTables" then change what it reads into. Also you will need a second bool variable to go with "haveHeadings" to use with the time tables.

Hope that helps,

Andy
Sorry for my late reply, I got a flu and I don't want to touch anything much (bad things in tropical country).
I cannot express my thanks to you, you really provoked my brain.
I'm not going to mark this question as done, maybe I'm surely going to have many more bugs and I will post them on here.
Thank you Andy, have good days!
Thinh
Helpppppppppppppppppppppppppp
In the function delete students, I have a thought that when I used vector, I could easily do like vector::erase and the data would be automatically updated.
However, this is an array and there is no such thing to erase an element. How can I erase an element from the array? I know that I also have to rewrite the file.
Last edited on
Hello thinhphucvang,

Using the C style arrays that you have the short explanation is to take everything to the right of what you want to delete and move it one left. And do not forget to change the variable that has the length of what the array use to hold. It needs to be one less.

I looked over the last code you posted and I do not see any function for delete. Let me see what you have done.

Hope that helps,

Andy
Pages: 123