bug at 74

bug at 74, it keeps repeating the statement instead of just reading the txt

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
  #include <iostream>
#include <fstream>
#include <stdlib.h>
#include <cstdlib> 
using namespace std;

class student{
    private:
    string name,college,course,student_no;
    public:
     void menu();
     void adding();
     void view();
};

void student::menu(){
    int opt;
    char x;
    cout << "---STUDENT MANAGEMENT APPLICATION---\n";
    cout << "1.Add student.\n";
    cout << "2.Delete Record.\n";
    cout << "3.Modify Record.\n";
    cout << "4.Search Record.\n";
    cout << "5.View Record.\n";
    cout << "6.Exit.\n";
    cout << "--------------------\n";
    cout << "Choose in the choices above\n";
    cout << "--------------------\n";
    while(!(cin >> opt)){
      cout << "Invalid option:";
      cin.clear();
      cin.ignore(100, '\n');
    }
    
    switch(opt){
        case 1:
            adding();
            cout << "Add another student? [Y/N]";
            cin >> x;
            while(!(x == 'Y' || x == 'y') && (x == 'n' || x == 'N')){
            cin.clear();
            cin.ignore(100,'\n');
            cout << "Must be Y/N only:";
            cin >> x;
            }
            break; 
       
        case 5: 
        view();
        break;   
        case 6:
        exit(0);
        default:
        cout << "Wrong input.";
    }
       
}

void student::adding(){
    fstream file;
    cout << "----ADD STUDENT----\n";
    cout << "Name:";
    cin >> name;
    cout << "College:";
    cin >> college;
    cout << "Course:";
    cin >> course;
    cout << "Student No.";
    cin >> student_no;
    file.open("Student Record.txt", ios::app | ios::out | ios::binary);
    file << " - " << name << " - " << college << " - " << course << " - " << student_no << "\n";
}

void student::view(){
    fstream file;
    int total = 0;
    file.open("Student Record.txt", ios::in);
    if(!file){
        cout << "NO DATA FOUND.";
    }else{
        file << " - " << name << " - " << college << " - " << course << " - " << student_no << "\n";
        while(!file.eof()){
          cout << "Student No." << total++ << "\n";
          cout << "Name: " << name << "\n";
          cout << "College: " << college << "\n";
          cout << "Course: " << course << "\n";
          cout << "Student ID no.: " << student_no << "\n";
          file << " - " << name << " - " << college << " - " << course << " - " << student_no << "\n";

        }
        if (total = 0){
            cout << "NO DATA FOUND.";
        }
    }
    file.close();
}

int main (){
    student project;
    project.menu();

}
If you mean the function at line 74 (to line 97) the code in the function doesn't read data, it outputs to the file at line 81. Use >>, not << for reading data from a file.
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
#include <iostream>
#include <fstream>
#include <regex>
#include <string>

void view() {

    if( std::ifstream file{ "Student Record.txt" } ) { // if the file is opened for input

        int slno = 0 ;
        std::string line ;
        while( std::getline( file, line ) ) { // for each line in the file

            // each record in the file was written with (student::adding: line #71):
            //     file << " - " << name << " - " << college << " - " << course << " - " << student_no << "\n";
            //     (note: fields do not contain embedded - characters)
            static const std::regex student_re( "^ - ([^-]+) - ([^-]+) - ([^-]+) - ([^-]+)$" ) ;
            //                                        name     college    course      id
             
            std::smatch match ;
            if( std::regex_match( line, match, student_re ) ) { // if line matches the pattern

                std::cout << "Serial No.: " << ++slno << '\n'
                          << "      Name: " << match[1] << '\n' // capture #1
                          << "   College: " << match[2] << '\n' // capture #2
                          << "    Course: " << match[3] << '\n' // capture #3
                          << "Student ID: " << match[4] << "\n\n" ; // capture #4
            }

            else {

                // ignore this unmatched line (or report an error)
            }
            
            // if( slno == 0 ) no records were read
        }
    }

    else std::cout << "failed to open input file.\n" ;
}
I like your regex-fu magic, JL. As usual I read in awe what can be done.
As a first refactor of the OP, consider:

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
#include <iostream>
#include <fstream>
#include <string>

using std::cout;
using std::cin;

constexpr char delim { '-' };

class Student {
private:
	std::string name, college, course, student_no;

	void adding();
	void view();

public:
	friend std::istream& operator>>(std::istream& is, Student& s) {
		std::getline(is, s.name, delim);
		std::getline(is, s.college, delim);
		std::getline(is, s.course, delim);
		std::getline(is, s.student_no);
		return is;
	}

	void menu();
};

void Student::menu() {
	for (unsigned opt {}; opt != 6; ) {
		cout << "\n---STUDENT MANAGEMENT APPLICATION---\n";
		cout << "1.Add student.\n";
		cout << "2.Delete Record.\n";
		cout << "3.Modify Record.\n";
		cout << "4.Search Record.\n";
		cout << "5.View All Records.\n";
		cout << "6.Exit.\n";
		cout << "--------------------\n";
		cout << "Choice: ";

		while (!(cin >> opt) || (opt < 1 || opt > 6)) {
			cout << "Invalid option. Please re-enter: ";
			cin.clear();
			cin.ignore(100, '\n');
		}

		switch (opt) {
			case 1:
				for (char x { 'Y' }; x == 'Y' || x == 'y'; ) {
					adding();
					cout << "Add another student? [Y/N]: ";

					while (!(cin >> x) || !(x == 'Y' || x == 'y' || x == 'n' || x == 'N')) {
						cin.clear();
						cin.ignore(100, '\n');
						cout << "Must be Y/N only: ";
					}
				}
				break;

			case 5:
				view();
				break;

			case 6:
				break;
		}
	}
}

void Student::adding() {
	cout << "----ADD STUDENT----\n";
	cout << "Name: ";
	std::getline(cin >> std::ws, name);

	cout << "College: ";
	std::getline(cin, college);

	cout << "Course: ";
	std::getline(cin, course);

	cout << "Student No.: ";
	std::getline(cin, student_no);

	if (std::ofstream file { "Student Record.txt", std::ios::app })
		file << name <<  delim << college << delim << course << delim << student_no << '\n';
	else
		cout << "Cannot open file\n";
}

void Student::view() {
	if (std::ifstream file { "Student Record.txt" }) {
		unsigned total {};

		while (file >> *this) {
			cout << "\nStudent No." << ++total << "\n";
			cout << "Name: " << name << "\n";
			cout << "College: " << college << "\n";
			cout << "Course: " << course << "\n";
			cout << "Student ID no.: " << student_no << "\n";
		}

		if (total == 0)
			cout << "NO DATA FOUND.";
	} else
		cout << "Cannot open file";
}

int main() {
	Student project;

	project.menu();
}


Note that option 5 actually displays all records - so the menu description has been changed.
Last edited on
Note though that this isn't a particularly good design as Student deals with adding/viewing multiple students - and it doesn't work well with const member functions. IMO it would be better to have a class say Students that dealt with all students and class Student that dealt with just one student.

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
#include <iostream>
#include <fstream>
#include <string>

using std::cout;
using std::cin;

constexpr char delim { '-' };

class Student {
	std::string name, college, course, student_no;

public:
	friend std::istream& operator>>(std::istream& is, Student& s) {
		std::getline(is, s.name, delim);
		std::getline(is, s.college, delim);
		std::getline(is, s.course, delim);
		std::getline(is, s.student_no);
		return is;
	}

	friend std::ostream& operator<< (std::ostream& os, const Student& s) {
		return os << s.name << delim << s.college << delim << s.course << delim << s.student_no << '\n';
	}

	void display() const {
		cout << "Name: " << name << "\n";
		cout << "College: " << college << "\n";
		cout << "Course: " << course << "\n";
		cout << "Student ID no.: " << student_no << "\n";
	}

	void input() {
		cout << "Name: ";
		std::getline(cin >> std::ws, name);

		cout << "College: ";
		std::getline(cin, college);

		cout << "Course: ";
		std::getline(cin, course);

		cout << "Student No.: ";
		std::getline(cin, student_no);
	}
};

class Students {
	void adding();
	void view() const;

	std::string filnam;

public:
	Students(const std::string& fn) : filnam(fn) {}

	void menu();
};

void Students::menu() {
	for (unsigned opt {}; opt != 6; ) {
		cout << "\n---STUDENT MANAGEMENT APPLICATION---\n";
		cout << "1.Add student.\n";
		cout << "2.Delete Record.\n";
		cout << "3.Modify Record.\n";
		cout << "4.Search Record.\n";
		cout << "5.View All Records.\n";
		cout << "6.Exit.\n";
		cout << "--------------------\n";
		cout << "Choice: ";

		while (!(cin >> opt) || (opt < 1 || opt > 6)) {
			cout << "Invalid option. Please re-enter: ";
			cin.clear();
			cin.ignore(100, '\n');
		}

		switch (opt) {
			case 1:
				for (char x { 'Y' }; x == 'Y' || x == 'y'; ) {
					adding();
					cout << "Add another student? [Y/N]: ";

					while (!(cin >> x) || !(x == 'Y' || x == 'y' || x == 'n' || x == 'N')) {
						cin.clear();
						cin.ignore(100, '\n');
						cout << "Must be Y/N only: ";
					}
				}
				break;

			case 5:
				view();
				break;

			case 6:
				break;
		}
	}
}

void Students::adding() {
	cout << "----ADD STUDENT----\n";

	Student s;

	s.input();

	if (std::ofstream file { filnam, std::ios::app })
		file << s;
	else
		cout << "Cannot open file\n";
}

void Students::view() const {
	if (std::ifstream file { filnam }) {
		unsigned total {};

		for (Student s; file >> s; ) {
			cout << "\nStudent No." << ++total << "\n";
			s.display();
		}

		if (total == 0)
			cout << "NO DATA FOUND.";
	} else
		cout << "Cannot open file";
}

int main() {
	Students project { "Student Record.txt" };

	project.menu();
}


Also note for an application like this, data would usually be first read from the file into say a std::vector, then manipulated as required, then written back to the file from the vector when all changes etc have been done.
Last edited on
CoreGuidelines:
By default, make member functions const

Reason: A member function should be marked const unless it changes the object’s observable state. This gives a more precise statement of design intent, better readability, more errors caught by the compiler, and sometimes more optimization opportunities.
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rconst-fct

FAQ:
Should I try to get things const correct “sooner” or “later”?

At the very, very, very beginning.
Back-patching const correctness results in a snowball effect: every const you add “over here” requires four more to be added “over there.”
Add const early and often.

https://isocpp.org/wiki/faq/const-correctness
Topic archived. No new replies allowed.