Student achievement management system (C + +)

Student achievement management system

1, Design task analysis

The main purpose of this topic is to manage students' grades. You can enter scores, query scores, delete score records, and rank scores. Facilitate the unified processing of students' scores after the examination.

2, Design of the overall scheme of student achievement management system

2.1 system database

The system uses a text document (. txt) to store data. The data items of the database mainly include: student number, name, grade, major, grade 1, grade 2, grade 3, average score and total score.

Each data is separated by a tab to facilitate subsequent writing and reading of data. Because there are many data items, I designed two classes to store these data items: grade class and student class.

2.2 class description

  • Score: including five data items: score 1, score 2, score 3, average score and total score.
  • Student: including five data items: student number, name, grade, major and grade.
  • Administrator class (Manager): there are two attributes: the path of the file storing records and the students of vector < student * > type, as well as various operations such as adding, deleting and querying grades. Students store the address of the object encapsulated by the records in the database file, manager CPP contains the main() function.

2.3 procedure flow

At the beginning of the program, the data in the text document is loaded into the variable length array students for later operation. Display the main page, let the user input and select, and then perform the corresponding functions.
The procedure flow chart is as follows:

2.4 function module

The system mainly has six functions: add function, delete function, modify function, search function, display function and sorting function.

2.4.1. Add function (add)

  • Execution process: first enter the student number and call read_ The number() function judges the input. If the student number is reasonable, call the checkId() function to check the student number. If it has been occupied and needs to be modified, call the update() function to modify it. If it is not occupied, start to input other data items and still call read_ The number () function checks these data items to see if they are reasonable. If all data items are reasonable, they are encapsulated, added to the variable length array students, and stored in the text document; If it is unreasonable, let the user re-enter. All input items are input errors for three times, which directly ends the function.

The procedure flow chart is as follows:

2.4.2 delete function (delete_)

  • Execution process: first call * * isEmpty() function to determine whether there is data. If there is data, let the user input the student number corresponding to the record to be deleted and call read_ The number() function determines whether the input is reasonable. Call findById() to find the location of the item to be deleted. The search is deleted in the variable length array students, and then called saveAll() * to save the deleted students to the file. If the search fails, the function ends.

The procedure flow chart is as follows:

2.4.3. Modify function (update)

  • Execution process: first call * * isEmpty() function to determine whether there is data. If there is data, enter the student number corresponding to the record to be modified and call read_ The number() function determines whether the input is reasonable. Call findById() to find the location of the item to be modified. The search is modified in the variable length array students, and then calls saveAll() * to save the modified students to the file. If the search fails, the function ends.

  • Modify operation: enter the number corresponding to the data item to be modified to modify. After modification, ask whether to continue to modify the record. If yes, continue to modify; Otherwise, the function ends.

The procedure flow chart is as follows:

2.4.4. Search function (query())

  • The search function can query findByName(), findByScore(), and findById() by student number. When searching by name, it is to search in order. First judge whether the length of the name is consistent, and then compare the name string by character. Comparing one character can narrow the range of possible results, find the final result set through layer by layer filtering, and return an array. When searching by score, half search is used to find all qualified results through recursion. When searching with the student number, the half search is also used, but because the student number is unique, there is no need for recursion.

  • Execution process: first call * * isEmpty() * * function to determine whether there is data. If there is data, the function page is displayed to allow the user to enter the number of the corresponding search method. Before performing the corresponding search operation, the data shall be sorted accordingly. If the query is successful, the query result will be returned and displayed, and the user will be asked whether to save it to the file, and the corresponding operation will be performed according to the input. If the query fails, the function ends.

The procedure flow chart is as follows:

2.4.5 display function

  • Execution process: first call * * isEmpty() * * function to determine whether there is data. If there is data, traverse the record array students loaded at the beginning of the program and print the records. Due to the large amount of data, the operation of pagination display is adopted.

  • Paging operation: only 10 records are displayed on a page by operating the subscript recorded in the array.

The procedure flow chart is as follows:

2.4.6 sorting function (order)

  • There are two sorting methods: sorting by student number and sorting by grade. You can select the sorting method by entering the corresponding number. Bubble sorting is used here, because when sorting by grade, other grades will be basically ordered after sorting once.

  • Execution process: first call isEmpty() function to determine whether there is data. If there is data, sort the loaded array of records at the beginning of the program. After sorting, call the **saveAll() * function to overwrite the original data into the file students.

The procedure flow chart is as follows:

2.5 core algorithm

2.5.1,getAll(),isEmpty()

  • getAll(): get the data, use the fstream file stream to read the data according to the defined file, and save it to the variable length array students.
while (fs >> id >> name >> grade >> pf >> score_1 >> score_2 >> score_3 >> avg >> sum) {
    Score score(score_1, score_2, score_3);
    students.push_back(new Student(id, name, grade, pf, score));
    i++;
}
  • isEmpty(): judge whether there is data. Yes, return 1; On the contrary, ask if you want to add a record and return 0.
if (students.empty()) { //No record 
    cout << "There is no record yet. Do you want to add a record? ";
    if (ch == "y" || ch == "Y") {
    	add();      //Perform the add operation
    }
}

2.5.2,getFileName(),save(),saveAll()

  • getFilename(): get the file name to assist the function of searching by name. Provide a file name when the search results need to be saved. The file name needs char * type, and the name type is string type, so use * * getFilename() to convert the name of string type into char array type, and then use the sprintf() * * function to format the string and splice a file name.
for (int i = 0; i < name.length(); i++)  
    name_c[i] = name[i]; //Convert string type to char array type 
name_c[name.length()] = '\0';
sprintf(filename, "name=%s.txt", name_c);
  • save(): save a single record. According to the stu passed in, it is written to the file with file stream.
fs << stu->getId() << "\t"
  << stu->getName() << "\t"
  << stu->getGrade() << "\t"
  << stu->getPf() << "\t"
  << stu->getScore().getScore_m() << "\t"
  << stu->getScore().getScore_c() << "\t"
  << stu->getScore().getScore_e() << "\t"
  << stu->getScore().getAvg() << "\t"
  << stu->getScore().getSum() << endl;
  • saveAll(): save multiple pieces of data. According to the variable length array stus and file name passed in, call the save() function to save one by one. The save() function uses the fsstream file stream to write the passed in content to the corresponding file.
for (int i = 0; i < stus.size(); i++) {
	save(stus.at(i), filename) 

2.5.3 verify input read_choose(),read_Number(),checkId()

Because the program needs to input data in many places, it is necessary to check the rationality of the data. Regular expressions are mainly used here. When the * * scanf() * * function reads data, match the data to judge whether it is reasonable.

  • Regular expression:% [] means reading in a character set, and "[" followed by "^" means taking non; * means not saving the data, that is, skipping the qualified string.

  • read_choose(): check whether the number entered when selecting the corresponding function is reasonable:

int ret1 = scanf("%d", &choose);   //Get the number and return 1; Otherwise, return 0
if (!ret1)   //If the number cannot be read, all the input contents will be read and filtered out
	scanf("%*[^'\n']");
scanf("%*[' ']");           //Read all the spaces
int ret2 = scanf("%[^'\n']", temp);  //^Indicates non. Gets all non newline characters
scanf("%*c"); //Read a character, * means it is not saved to the variable. That is, get a newline character 
  • read_Number(): check whether the input data is reasonable. The data here includes students' grades and student numbers. It is mainly used to check the corresponding input when adding records and finding records.
if (!flag)   //When flag==0, read the student number; Otherwise, read the score
	ret1 = scanf("%ld", &id);
else
	ret1 = scanf("%lf", &score);
if (!ret1) { 
	scanf("%*[^'\n']");
}
scanf("%*[' ']"); 
int ret2 = scanf("%[^\n]", temp);
scanf("%*c"); 
  • checkId(): check whether the student number has been occupied. Call the * * findById() * * function to find it. If the search is successful, it indicates that the student number has been occupied. Ask whether you want to modify the information of the student number. If the lookup fails, - 1 is returned.
findById(id, index); //Find with this student number
if (index != -1) {  //If the search is successful, the student number has been occupied
    cout << "The student of this student number has records. Do you want to modify it?\n input'y'Modify, enter other and return.";
    string choose;
    cin >> choose;
    if (choose == "y" || choose == "Y") {
        system("cls");
        update(id);     //Modify record
    }
}
return index;

2.5.4 pagination display

Traverse the variable length array students and control the subscript so that only 10 records are displayed per page. According to 10 records per page and the subscript of the current record in the array, the current page number and total pages are displayed at the bottom of each page. Enter the corresponding instruction to view the previous page, the next page and jump to the specified page. i is the subscript of the lowest record of the currently displayed page in the variable length array students.

  • When viewing the previous page, you need to judge whether there will be a previous page, that is, whether it is the first page (there is no previous page). If there is a previous page, make I = I - (I% 10) - 11, that is, find the subscript of the first record on the previous page in the variable length array students minus 1, because it will be followed by 1.

  • When viewing the next page, you need to judge whether there will be a next page, that is, whether it is the last page (there is no next page).

  • To jump to the page of the corresponding page number, the * * atoi() * * function in the string library is used, which converts the input string into a number, and then assigns it to the variable representing the subscript of the record, so that you can directly jump to the corresponding page.

page= atoi(cho.c_str());        //Convert string to number
if (page >= 1 && page <= ((count - 1) / 10 + 1)) 
	i = (page - 1) * 10 - 1;       //Skip to the corresponding page number
else if (cho == "n" || cho == "N") {  //Enter n or n for the next page 
    if (i == count - 1) {
        cout << "It is the last page at present. There is no next page!\n";
        //Count starts from 1 and i starts from 0, so count starts with - 1
        i = (count - 1) - ((count - 1) % 10) - 1;
    }
}
else if (cho == "s" || cho == "S") {  //Enter s or s for the previous page 
    i = i - (i % 10) - 11;       //Subscript-1 of the first record on the previous page 
    if (i < -1) {
        cout << "It is the first page at present. There is no previous page!\n";
        i = -1;      //Reassign to the subscript-1 of the first record on the first page
    }
}
else            //Enter another to exit directly
	break;

2.5.5 sorting

Since the results are sorted once, other results become basically orderly, so bubble sorting is used here. Sorting is divided into sorting by grades and sorting by student number, and its implementation method is the same.

for (int i = 0; i < count - 1; i++) {//Sort by grade (from large to small)
    int flag_break = true;
    for (int j = 0; j < count - 1 - i; j++) {
        if (students.at(j + 1)->getScore(ch) > students.at(j)->getScore(ch)) {
            swap(j, j + 1);  //Swap two objects
            flag_break = false;
    	}
    }
    if (flag_break) break;   
}

2.5.6 search

When searching by name, we use sequential search, and when searching by score or student number, we use half search.

  • Search by name findByName(): len is the length of the name string. When searching in order, first compare whether the lengths of the two names are consistent, and then compare the first character. If they are the same, they will be added to the result array. Then compare the second character of the possible result in the result array with the parameter name. If it is the same, add it to the emptied result array and compare all the characters of the name string in turn. The final result array is the final result.
while (ct < len) {	//ct is the subscript of the name string, and len is the length of the name string
    temp = result;
    result = temp_null;
    for (int i = 0; i < temp.size(); i++) {
        string name_ = temp.at(i)->getName();
        if (name_.length() == len) {	//Compare the same length
            if (name_[ct] == name[ct])
                result.push_back(temp.at(i));
        }
    }
    ct++;
}
  • Find findById() by student number: it is unique when the student number is specified, so you can directly use half search.
while (left <= right) {
    mid = (left + right) / 2;
    if (students.at(mid)->getId() == id) {
    index = mid;
    return students.at(mid);
    }
    else if (id < students.at(mid)->getId())
    right = mid - 1;
    else
    left = mid + 1;
}
index = -1; 				//-1 means query failed 
  • Find findByScore(): because the score is not unique, there may be multiple results, so the recursion of half search is used here. First find a result, and then half search the left and right parts to find all qualified results.
while (left <= right) {
	mid = (left + right) / 2;
	if (students.at(mid)->getScore(flag) == score) {
		//index=mid;
		temp.push_back(students.at(mid));
		Search_bin(temp, flag, score, low, mid - 1);	//Recursive left half 
		Search_bin(temp, flag, score, mid + 1, high);	//Recursive right half
		break; 											//Exit loop 
	}
	else if (score > students.at(mid)->getScore(flag))
		right = mid - 1;
	else
		left = mid + 1;
}

source code

include.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream> 		// File stream
#include<cstdlib>		//atoi,system
#include<vector> 		// Variable length array
#include<iomanip> 		// Control cout output format 
#include<windows. h> 		// Sleep() and color settings
using namespace std;

score.h

#pragma once
#include "include.h"
class Score {
private:
	double score_m;	//Mathematics achievement 
	double score_c;	//grade scores of Chinese 
	double score_e;	//English achievement
	double avg;		//Average score 
	double sum;		//Total score 
public:
	Score();		//Nonparametric structure 
	Score(double m, double c, double e);
	void setScore_m(double score_m);
	double getScore_m();
	void setScore_c(double score_c);
	double getScore_c();
	void setScore_e(double score_e);
	double getScore_e();
	double getAvg();	//Get average score
	double getSum();	//Get total score
	void show_score();	//Show score
};

score.cpp

#include"score.h"

Score::Score() {		//non-parameter constructor  
}
//Constructor 
Score::Score(double m, double c, double e) {
	this->score_m = m;
	this->score_c = c;
	this->score_e = e;
	this->avg = 1; //getAvg();
	this->sum = 1;//getSum();
}

void Score::setScore_m(double score_m) {
	this->score_m = score_m;
}
double Score::getScore_m() {
	return this->score_m;
}

void Score::setScore_c(double score_c) {
	this->score_c = score_c;
}
double Score::getScore_c() {
	return this->score_c;
}

void Score::setScore_e(double score_e) {
	this->score_e = score_e;
}
double Score::getScore_e() {
	return this->score_e;
}

//Show score information
void Score::show_score() {
	cout << "Math scores:" << this->score_m << endl;
	cout << "Language achievement:" << this->score_c << endl;
	cout << "English score:" << this->score_e << endl;
	printf("Average score:%.2lf\n", getAvg());
	printf("Total score:%.2lf\n", getSum());
}

//Calculate average score
double Score::getAvg() {
	double avg = (score_m + score_c + score_e) / 3;
	return avg;
}

//Calculate total score
double Score::getSum() {
	double sum = score_m + score_c + score_e;
	return sum;
}

student.h

#pragma once
#include "score.h"

class Student {
private:
	long id;		//Student number 
	string name;	//full name 
	string grade;	//grade 
	string pf;		//major
	Score score;	//achievement 
public:
	Student();
	Student(long id, string name, string grade, string pf, Score score);
	void setId(long id);
	long getId();
	void setName(string name);
	string getName();
	void setGrade(string grade);
	string getGrade();
	void setPf(string pf);
	string getPf();
	void setScore(Score score);
	void setScore(double score1, double score2, double score3);
	Score getScore();			//Get score object 
	double getScore(int num);	//Get the score of the corresponding serial number 
};

student.cpp

#include "student.h"

//non-parameter constructor  
Student::Student() {
}
//Parameterized constructor 
Student::Student(long id, string name, string grade, string pf, Score score) {
	this->id = id;
	this->name = name;
	this->grade = grade;
	this->pf = pf;
	this->score = score;
}
void Student::setId(long id) {
	this->id = id;
}
long Student::getId() {
	return this->id;
}

void Student::setName(string name) {
	this->name = name;
}
string Student::getName() {
	return this->name;
}

void Student::setGrade(string grade) {
	this->grade = grade;
}
string Student::getGrade() {
	return this->grade;
}

void Student::setPf(string pf) {
	this->pf = pf;
}
string Student::getPf() {
	return this->pf;
}

void Student::setScore(Score score) {
	this->score = score;
}

void Student::setScore(double score1, double score2, double score3) {
	if (score1 > 0)
		this->score.setScore_m(score1);
	if (score2 > 0)
		this->score.setScore_c(score2);
	if (score3 > 0)
		this->score.setScore_e(score3);
}
Score Student::getScore() {
	return this->score;
}

double Student::getScore(int num) {
	switch (num) {
	case 1:		//Total score 
		return getScore().getSum();
	case 2:		//Mathematics achievement 
		return getScore().getScore_m();
	case 3:		//grade scores of Chinese 
		return getScore().getScore_c();
	case 4:		//English achievement 
		return getScore().getScore_e();
	}
}

SMS.h

#pragma once
#include "student.h"
#define _CRT_SECURE_NO_WARNINGS

class Manager {
public:
	static const char* getPath(); 				//Gets the file path where the record is stored
	vector<Student*> getStudents();				//Get all records

	void clear();								//Clear screen 
	void show_back(int flag = 0);				//Show return information
	void show_to();								//Display entry information

	int checkId(long id);						//Check whether the student number is the same
	double read_Number(long& id);				//Read the score and check whether the score is reasonable
	void add();									//Add record 

	void delete_();								//Delete record

	int read_choose(int left, int right);		//Read selection 
	int update(long id = -1);					//Modify record
	int update(Student* stu);					//Modify record

	int isEmpty();								//Judge whether the record is empty 
	void getFilename(string name, char filename[]);				//Get file name
	void Search_bin(vector<Student*>& temp, int flag, double score, int left, int right);	//Half search 
	Student* findById(long id, int& index);		//find record
	vector<Student*> findByScore(double score, int& index, int flag);
	vector<Student*> findByName(string name, int& index);
	void query(int cho);						//Query function 

	void show(Student* stu);						//Show single record
	void color(int i);
	void showHeader();							//Display header 
	void display(vector<Student*> stus, int flag = 0);//Show all records 

	void swap(int i, int j); 					//exchange 
	void order(int ch, int flag = 0);			//Sorting function

	string isSave();							//Do you want to save 
	void save(Student* stu, int flag, const char* filename = "stu_score.txt");	//Save a single record
	void saveAll(vector<Student*> stus, const char* filename = "stu_score.txt");	//Save multiple records 

	int getAll();								//Get all records 
private:
	static const char* path; 					//The path to the file where the record is stored
	vector<Student*> students;					//Keep all the records
};

SMS.cpp

#include "SMS.h"

//Global variable. The whole program has only one Manager object
Manager manager;

//Initialize class static member variables. Save path of all records 
const char* Manager::path = "stu_score.txt";

//Gets the file path where the record is stored 
const char* Manager::getPath() {
	return path;
}

//Get all records
vector<Student*> Manager::getStudents() {
	return students;
}

//Clear screen 
void Manager::clear() {
	system("pause");
	system("cls");
}

//Get all records, encapsulate them, and return the total number of records
int Manager::getAll() {
	long id;
	string name, grade, pf;
	double score_1, score_2, score_3, avg, sum;	//achievement
	int i = 0;

	fstream fs;
	fs.open(getPath(), ios::in);	//The first parameter requires a char * type, not a string type 
	while (fs >> id >> name >> grade >> pf >> score_1 >> score_2 >> score_3 >> avg >> sum) {
		Score score(score_1, score_2, score_3);
		students.push_back(new Student(id, name, grade, pf, score));
		i++;
	}
	fs.close();

	return students.size();	//Returns the total number of records
}

//Check whether the student number has been used
int Manager::checkId(long id) {
	order(5, 1);			//Sort by student number first
	int count = students.size();
	int index;
	findById(id, index);	//Find with this student number
	if (index != -1) {		//If the search is successful, the student number has been occupied
		cout << "The student of this student number has records. Do you want to modify it?\n input'y'Modify, enter other and return.";
		string choose;
		cin >> choose;
		if (choose == "y" || choose == "Y") {
			system("cls");
			update(id);			//Modify record
		}
	}
	
	return index;
}

//Use regular expressions to determine whether the input is correct
//When id==0, read the student number; Otherwise, read the score
double Manager::read_Number(long& id)
{
	long flag = id;	//0: student number; 1: Achievements; 2: Total score
	double score = 101;
	int ct = 3;
	while (true) {
		char temp[32];	//Save non numeric characters
		//Get the number and return 1; Otherwise, return 0
		int ret1;
		if (!flag)
			ret1 = scanf("%ld", &id);
		else
			ret1 = scanf("%lf", &score);
		if (!ret1) {	//If no number is read, all the input contents are obtained and filtered out
			scanf("%*[^'\n']");
		}
		scanf("%*[' ']");	//Read the space
		//^Indicates non. That is, get all characters that are not newline characters
		//Get, return 1; Otherwise, return 0
		int ret2 = scanf("%[^\n]", temp);
		scanf("%*c");	//Read a character, * means it is not saved to the variable. That is, get a newline character

		//A number is read and there are no non newline characters after the number
		if (ret1 && !ret2 && flag == 0 && (id >= 1000000 && id <= 9999999))
			return score;	//Student number
		else if (ret1 && !ret2 && flag == 1 && (score >= 0 && score <= 100))
			return score;	//achievement
		else if (ret1 && !ret2 && flag == 2 && (score >= 0 && score <= 300))
			return score;	//Total score
		else if (ct == 0) {
			return -1;	//Input error three times, return 1
		}
		else {
			cout << "Input error, please re-enter(also" << ct-- << "Second chance): ";
		}
	}
}

//Add record 
void Manager::add() {
	Student* stu = new Student;	//Student object 
	long id = 0;	//Student number 
	long temp = 1;	//Temporary variable 
	string name;	//full name 
	string grade;	//grade 
	string pf;		//major
	double score1;	//Mathematics achievement 
	double score2;	//grade scores of Chinese 
	double score3; 	//English achievement 

	cout << "Please enter 7 digits of student ID (e.g. 2021000):";
	if (read_Number(id) == -1) {
		clear();
		return;
	}

	if (checkId(id) == -1) {	//The student number is not occupied
		stu->setId(id);
		cout << "Please enter the student's name, grade and major respectively: \n";
		cin >> name >> grade >> pf;
		stu->setName(name);
		stu->setGrade(grade);
		stu->setPf(pf);

		cout << "Please enter the student's math score:";
		score1 = read_Number(temp);
		if (score1 == -1) {
			cout << "Failed to add!\n";
			clear();
			return;
		}

		cout << "Please enter the student's language score:";
		score2 = read_Number(temp);
		if (score2 == -1) {
			cout << "Failed to add!\n";
			clear();
			return;
		}

		cout << "Please enter the student's English score:";
		score3 = read_Number(temp);
		if (score3 == -1) {
			cout << "Failed to add!\n";
			clear();
			return;
		}

		Score score(score1, score2, score3);	//Achievement object 
		stu->setScore(score);

		students.push_back(stu);				//Add to the global variable students
		save(stu, 1);							//Keep records
		cout << "\n The information of the added record is as follows:\n";
		show(stu);								//Display record 
		clear();
	}
	else
		system("cls");
}

//Show single record 
void Manager::show(Student* stu) {
	cout << "Student No.:" << stu->getId() << endl;
	cout << "full name:" << stu->getName() << endl;
	cout << "Grade:" << stu->getGrade() << endl;
	cout << "Major:" << stu->getPf() << endl;
	stu->getScore().show_score();
}

//Save a single record
//flag==1, for additional saving, flag==0, for overwriting the previous record 
void Manager::save(Student* stu, int flag, const char* filename) {
	fstream fs;
	if (flag == 1) {
		//Append write. Add ios::app to the original ios::out
		fs.open(filename, ios::out | ios::app);
	}
	else {
		//The existing records will be overwritten 
		fs.open(filename, ios::out);
	}

	//Write to file 
	fs << stu->getId() << "\t"
		<< stu->getName() << "\t"
		<< stu->getGrade() << "\t"
		<< stu->getPf() << "\t"
		<< stu->getScore().getScore_m() << "\t"
		<< stu->getScore().getScore_c() << "\t"
		<< stu->getScore().getScore_e() << "\t"
		<< stu->getScore().getAvg() << "\t"
		<< stu->getScore().getSum() << endl;

	fs.close();
}

//Save multiple records
void Manager::saveAll(vector<Student*> stus, const char* filename) {
	for (int i = 0; i < stus.size(); i++) {
		if (i == 0)
			save(stus.at(i), 0, filename);		//Overwrite the original record first 
		else
			save(stus.at(i), 1, filename);		//Append record 
	}
}

//Judge whether the record is empty 
//Null: returns 0; Otherwise, return 1
int Manager::isEmpty() {
	if (students.empty()) {	//No record 
		cout << "There is no record yet. Do you want to add a record?(input y Add, enter other (return)";
		string ch;
		cin >> ch;
		if (ch == "y" || ch == "Y") {
			add();	//Perform the add operation
		}
		return 0;
	}

	return 1;
}

//Display header 
void Manager::showHeader() {
	cout << left;	//Left aligned, right aligned by default 
	cout << "-----------+---------+---------+---------------+-----------+-----------+-----------+---------+---------+\n";
	cout << "| "; color(14); cout << setw(9) << "Student number"; color(3); cout << "| ";
	color(14); cout << setw(8) << "full name"; color(3); cout << "| ";
	color(14); cout << setw(8) << "grade"; color(3); cout << "| ";
	color(14); cout << setw(14) << "major"; color(3); cout << "| ";
	color(14); cout << setw(10) << "Mathematics achievement"; color(3); cout << "| ";
	color(14); cout << setw(10) << "grade scores of Chinese"; color(3); cout << "| ";
	color(14); cout << setw(10) << "English achievement"; color(3); cout << "| ";
	color(14); cout << setw(8) << "average"; color(3); cout << "| ";
	color(14); cout << setw(8) << "Total score"; color(3); cout << "| \n";
}

//Set color 
void Manager::color(int i) {
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), i);
}

//Show multiple records
//flag defaults to 0
//When flag==1, the query result is displayed, and the screen is not clear when returning
void Manager::display(vector<Student*> stus, int flag) {
	if (!isEmpty()) 			//Determine whether there are records 
		return;
	system("cls");
	showHeader();				//Display header 
	int count = stus.size();	//Total records
	int i = 0;

	//paging operation 
	while (i < count) {
		cout << "-----------+---------+---------+---------------+-----------+-----------+-----------+---------+---------+\n";
		cout << left;	//Left aligned, right aligned by default 
		cout << "| " << setw(9) << stus.at(i)->getId() << "| "
			<< setw(8) << stus.at(i)->getName() << "| "
			<< setw(8) << stus.at(i)->getGrade() << "| "
			<< setw(14) << stus.at(i)->getPf() << "| ";
		printf("%-10.1lf| ", stus.at(i)->getScore().getScore_m());
		printf("%-10.1lf| ", stus.at(i)->getScore().getScore_c());
		printf("%-10.1lf| ", stus.at(i)->getScore().getScore_e());
		printf("%-8.1lf| %-8.1lf|\n", stus.at(i)->getScore().getAvg(), stus.at(i)->getScore().getSum());
		Sleep(25);
		//Output the page number and check whether the input is correct
		if ((i + 1) % 10 == 0 || i == count - 1) {
			cout << "-----------+---------+---------+---------------+-----------+-----------+-----------+---------+---------+\n";
			cout << right << setw(41) << "The first" << i / 10 + 1 << "page/common" << (count - 1) / 10 + 1 << "page\n";
			cout << "\n input's'View the previous page and enter'n'To view the next page, enter 1-" << (count - 1) / 10 + 1 << "Turn the page and enter other information to return.";
			string cho;
			cin >> cho;
			if (atoi(cho.c_str()) >= 1 && atoi(cho.c_str()) <= ((count - 1) / 10 + 1)) {
				i = (atoi(cho.c_str()) - 1) * 10 - 1;	//Convert a string to a number and skip to the corresponding page number 
			}
			else if (cho == "n" || cho == "N") {		//Enter n or n for the next page 
				if (i == count - 1) {
					cout << "It is the last page at present. There is no next page!\n";
					//Count starts from 1 and i starts from 0, so count starts with - 1
					i = (count - 1) - ((count - 1) % 10) - 1;
					system("pause");
				}
			}
			else if (cho == "s" || cho == "S") {	//Enter s or s for the previous page 
				i = i - (i % 10) - 11;				//Subscript-1 of the first record on the previous page 
				if (i < -1) {
					cout << "It is the first page at present. There is no previous page!\n";
					i = -1;			//Reassign to the subscript-1 of the first record on the first page
					system("pause");
				}
			}
			else {			//Enter another to exit directly
				if (!flag)	//When flag==1, the query result is displayed, and the screen is not clear when returning
					show_back();
				break;
			}
			system("cls");
			showHeader();	//If the loop is not exited, the next page is displayed. Here is the display header 
		}
		i++;
	}
}

//Search records (query by student number) 
Student* Manager::findById(long id, int& index) {
	//Before finding records, first arrange the records according to the student number. The second parameter is 1, which means that after sorting, you need to query
	order(5, 1);
	int count = students.size();	//total

	//Binary query 
	int left = 0;
	int right = count - 1;
	int mid = 0;
	while (left <= right) {
		mid = (left + right) / 2;
		if (students.at(mid)->getId() == id) {
			index = mid;
			return students.at(mid);
		}
		else if (id < students.at(mid)->getId())
			right = mid - 1;
		else
			left = mid + 1;
	}
	index = -1; 				//-1 means query failed 
	return NULL;
}


//Half search 
//temp: an array that holds search results
//flag: flag search method (search by total score, math score, etc.)
//Score: the score to find
//Left: find the left boundary of the interval
//Right: find the right boundary of the interval
void Manager::Search_bin(vector<Student*>& temp, int flag, double score, int left, int right) {
	int low = left;		//Save rightmost subscript 
	int high = right;	//Save leftmost subscript
	int mid;
	while (left <= right) {
		mid = (left + right) / 2;
		if (students.at(mid)->getScore(flag) == score) {
			//index=mid;
			temp.push_back(students.at(mid));
			Search_bin(temp, flag, score, low, mid - 1);	//Recursive left half 
			Search_bin(temp, flag, score, mid + 1, high);	//Recursive right half
			break; 											//Exit loop 
		}
		else if (score > students.at(mid)->getScore(flag))
			right = mid - 1;
		else
			left = mid + 1;
	}
}

//Find records (query by score)
//The parameter flag represents the sorting method:
//1: Sort by total score
//2: Sort by math score
//3: Sort by Chinese score
//4: Sort by English score
vector<Student*> Manager::findByScore(double score, int& index, int flag) {
	vector<Student*> temp;

	//Before finding records, first arrange them according to their grades. The second parameter is 1, which means that after sorting, you need to query
	order(flag - 1, 1);
	int count = students.size();	//total 
	Search_bin(temp, flag - 1, score, 0, count - 1);	//Binary search 
	if (temp.size() == 0)
		index = -1;		//Search failed
	return temp;
}

//Query by name
vector<Student*> Manager::findByName(string name, int& index) {
	cout << "Please wait";
	Sleep(200); cout << "."; Sleep(200); cout << "."; Sleep(200); cout << ".\n";
	vector<Student*> result;
	int len = name.length();
	result = students;
	vector<Student*> temp, temp_null;	//temp temporarily saves all possible results
	int ct = 0;							//Subscript of first name string
	while (ct < len) {
		temp = result;
		result = temp_null;
		for (int i = 0; i < temp.size(); i++) {
			string name_ = temp.at(i)->getName();
			if (name_.length() == len) {	//Compare the same length
				if (name_[ct] == name[ct])
					result.push_back(temp.at(i));
			}
		}
		ct++;
	}
	if (result.size() == 0)
		index = -1;		//Search failed
	return result;
}

//Ask if you want to save 
string Manager::isSave() {
	cout << "Do you want to save the query results to a file?\n input y Save, enter other and return.";
	string cho;
	cin >> cho;
	return cho;
}

//Get file name 
void Manager::getFilename(string name, char filename[]) {
	char name_c[16];
	for (int i = 0; i < name.length(); i++)
		//Convert string type to char array type
		name_c[i] = name[i];		
	name_c[name.length()] = '\0';

	sprintf(filename, "name=%s.txt", name_c);
}

//Query function 
void Manager::query(int cho) {
	if (cho == 0) {
		system("cls");
		return;		//Direct return 
	}
	long id = 0;	//Student number 
	double score;	//fraction 
	string name;	//name
	Student* stu = new Student; 	//Student object
	vector<Student*> stus;
	char* filename = (char*)malloc(sizeof(char) * 64);	//file name 
	int index;		//Return subscript, - 1 means query failed 

	switch (cho) {
	case 1:
		cout << "Please enter your first name:";
		cin >> name;
		stus = findByName(name, index);
		break;
	case 2:	//Total score
		cout << "Please enter your grade:";
		id = 2;
		score = read_Number(id);
		if (score == -1) {
			system("cls");
			return;
		}
		stus = findByScore(score, index, cho);
		break;
	case 3:	//achievement
	case 4:
	case 5:
		cout << "Please enter your grade:";
		id = 1;
		score = read_Number(id);
		if (score == -1) {
			system("cls");
			return;
		}
		stus = findByScore(score, index, cho);
		break;
	case 6:
		cout << "Please enter the 7 digits of the student number to be queried (e.g. 2021000):";
		if (read_Number(id) == -1) {
			system("cls");
			return;
		}
		stu = findById(id, index);
		break;
	}

	if (index == -1) {
		cout << "Query failed, there is no student!" << endl;
	}
	else if (cho == 6) {
		cout << "Query succeeded! The student's grade information is as follows:\n\n";
		show(stu);
		sprintf(filename, "id=%.2ld.txt", id);
		string ret = isSave();
		if (ret == "y" || ret == "Y") {
			save(stu, 0, filename);	//Parameter 0 is to overwrite the original data
			cout << "Data saved to file: " << filename << endl;
		}
	}
	else {
		cout << "Query succeeded!" << endl;
		system("pause");			//Pause first
		display(stus, 1);
		if (cho == 1) {
			getFilename(name, filename);
		}
		else
			sprintf(filename, "score=%.2lf.txt", score);
		string ret = isSave();
		if (ret == "y" || ret == "Y") {
			saveAll(stus, filename);
			cout << "Data saved to file: " << filename << endl;
		}
	}

	clear();
}

//Delete record
void Manager::delete_() {
	if (!isEmpty()) { 				//Determine whether there are records
		system("cls");
		return;
	}
	int count = students.size();	//total 

	long temp = 0;
	cout << "Please enter 7 digits of the student number of the record to be deleted (e.g. 2021000):";
	if (read_Number(temp) == -1) {	//Student ID reading failed 
		system("cls");
		return;
	}
	cout << "Please wait"; cout << "."; Sleep(200); cout << "."; Sleep(200); cout << ".\n"; Sleep(200);
	int index;						//Subscript of record to be deleted 
	findById(temp, index);
	if (index == -1) {
		cout << "Record deletion failed! There are no students with the student number.\n";
		clear();
		return;
	}
	vector<Student*>::iterator it;	//Get iterator 
	it = students.begin();
	while (index > 0) {	//Find the location of the iterator 
		it++;
		index--;
	}
	students.erase(it);	//Delete record in array

	saveAll(students);	//Keep all records
	string cho;
	cout << "Record deleted successfully!\n To view all records, please enter y,Please enter other characters when returning:";
	cin >> cho;
	if (cho == "y" || cho == "Y")
		display(students);			//Display deleted records 
	system("cls");
}

//Use regular expressions to determine whether the input is correct
int Manager::read_choose(int left, int right) {
	int ct = 3;
	int choose = -1;
	cout << "Please select the number of the corresponding function(" << left << " - " << right << "): ";
	while (true) {
		char temp[32];	//Save non numeric characters
		//Get the number and return 1; Otherwise, return 0
		int ret1 = scanf("%d", &choose);
		if (!ret1)	//If the number cannot be read, all the input contents will be read and filtered out
			scanf("%*[^'\n']");
		scanf("%*[' ']");	//Read the space
		//^Indicates non. That is, get all characters that are not newline characters
		//Get, return 1; Otherwise, return 0
		int ret2 = scanf("%[^'\n']", temp);
		scanf("%*c");	//Read a character, * means it is not saved to the variable. That is, get a newline character

		//A number is read and there are no non newline characters after the number
		if (ret1 && !ret2 && choose >= left && choose <= right) {
			return choose;
		}
		else if (ct == 0)
			return -1;	//Input error three times, return - 1
		else {
			cout << "Input error, please re-enter(also" << ct-- << "Second chance): ";
		}
	}
}

//Modify record
int Manager::update(Student* stu) {
	cout << "The student's information is as follows:\n\n";
	show(stu);
	int choose;
	cout << "\n=======================================================" << endl;
	//Cout < < ----------------- welcome to the modification function ---------------------- < < endl;
	cout << "    @          [1]Modify name                      @    " << endl;
	cout << "    @          [2]Modify grade                      @    " << endl;
	cout << "    @          [3]Modify specialty                      @    " << endl;
	cout << "    @          [4]Modify math scores                  @    " << endl;
	cout << "    @          [5]Revise Chinese scores                  @    " << endl;
	cout << "    @          [6]Revise English scores                  @    " << endl;
	cout << "    @          [0]Return to management system                  @    " << endl;
	cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;

	choose = read_choose(0, 6);
	if (choose == 0 || choose == -1) {
		manager.show_back();
		return -2;
	}

	string name, grade, pf;			//Name, grade, major 
	long temp = 1;					//Temporary variable. 1 indicates the reading result
	double score1, score2, score3;	//achievement 
	switch (choose) {
	case 0:
		return -2;
	case 1:
		cout << "\n Please enter the student's new name: ";
		cin >> name; stu->setName(name);
		break;
	case 2:
		cout << "\n Please enter the student's new grade: ";
		cin >> grade; stu->setGrade(grade);
		break;
	case 3:
		cout << "\n Please enter the student's new major: ";
		cin >> pf; stu->setPf(pf);
		break;
	case 4:
		cout << "Please enter the student's new math score:";
		score1 = read_Number(temp);
		if (score1 == -1)
			return -1;
		stu->setScore(score1, -1, -1);
		break;
	case 5:
		cout << "Please enter the student's new language score:";
		score2 = read_Number(temp);
		if (score2 == -1)
			return -1;
		stu->setScore(-1, score2, -1);
		break;
	case 6:
		cout << "Please enter the student's new English score:";
		score3 = read_Number(temp);
		if (score3 == -1)
			return -1;
		stu->setScore(-1, -1, score3);
		break;
	}
	return 0;
}

//Modify record function. id is - 1 by default. If there are other student numbers passed in, other student numbers will be used 
int Manager::update(long id) {
	if (!isEmpty()) {
		system("cls");
		return 0;
	}
	long temp;
	if (id == -1) {
		temp = 0;	//0 means reading the student number
		cout << "Please enter the 7-digit student number of the record to be modified (e.g. 2021000):";
		if (read_Number(temp) == -1) {
			system("cls");
			return 0;
		}
	}
	else
		temp = id;

	int index;
	findById(temp, index);
	if (index != -1) {
		string choose;
		do {
			int ret = update(students.at(index));	//Return value 
			if (ret == -1) {
				cout << "Modification failed!\n";
				clear();
				return 0;
			}
			else if (ret == -2) {
				system("cls");
				return 0;
			}
			saveAll(students);				//Keep all records 
			system("cls");
			cout << "\n Modification succeeded! The new information is as follows:\n\n";
			show(students.at(index));		//Displays the modified record
			cout << "Do you want to continue modifying?\n input y Continue, enter another return.";
			cin >> choose;
			system("cls");
		} while (choose == "y" || choose == "Y");
	}
	else {
		cout << "Modification failed, there are no students with this student number!\n";
		system("pause");
	}
		
	system("cls");
	return 1;
}

//Swap two objects 
void Manager::swap(int i, int j) {
	Student* stu = students.at(i);
	students.at(i) = students.at(j);
	students.at(j) = stu;
}

//Sorting function (select sorting) returns an array for easy search 
//If the parameter ch is the specified sorting method and the parameter flag is 1, the next step is to query or add 
void Manager::order(int ch, int flag) {	//flag is 0 by default (the default parameter should be put later) 
	if (ch == 0) {
		system("cls");
		return;				//Direct return 
	}

	//Bubble sorting
	int count = students.size();	//total 
	if (ch != 5) {	//Sort by grade (from large to small)
		for (int i = 0; i < count - 1; i++) {
			int flag_break = true;
			for (int j = 0; j < count - 1 - i; j++) {
				if (students.at(j + 1)->getScore(ch) > students.at(j)->getScore(ch)) {
					swap(j, j + 1);	//Swap two objects
					flag_break = false;
				}
			}
			if (flag_break)
				break;
		}
	}
	else {			//Sort by student number (from small to large)
		for (int i = 0; i < count - 1; i++) {
			int flag_break = true;
			for (int j = 0; j < count - 1 - i; j++) {
				if (students.at(j + 1)->getId() < students.at(j)->getId()) {
					swap(j, j + 1);			//Swap two objects
					flag_break = false;
				}
			}
			if (flag_break)
				break;
		}
	}
	if (!flag) {
		cout << "Please wait";
		Sleep(200); cout << "."; Sleep(200); cout << "."; Sleep(200); cout << ".\n";
	}
	saveAll(students);			//Keep records
	if (!flag) {				//If the sorted operation is not a query, all the sorted contents will be displayed 
		display(students);
		system("cls");
	}
}

//Show return information
void Manager::show_back(int flag) {
	flag == 1 ? cout << "About to exit the management system" : cout << "About to return";
	cout << "."; Sleep(300);
	cout << "."; Sleep(300);
	cout << "."; Sleep(300);
	system("cls");
}

//Display entry information
void Manager::show_to() {
	system("cls");
	cout << "Please wait";
	cout << "."; Sleep(200);
	cout << "."; Sleep(200);
	cout << "."; Sleep(200);
	system("cls");
}

//Select how to sort 
int order_ch() {
	if (!manager.isEmpty())
		return 0;
	int choose;
	cout << "=======================================================" << endl;
	cout << "----------------Welcome to the sorting function-----------------------" << endl;
	cout << "    @          [1]Sort by total score                  @    " << endl;
	cout << "    @          [2]Sort by math score                @    " << endl;
	cout << "    @          [3]Sort by Chinese score                @    " << endl;
	cout << "    @          [4]Sort by English score                @    " << endl;
	cout << "    @          [5]Sort by student number                    @    " << endl;
	cout << "    @          [0]Return to management system                  @    " << endl;
	cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
	choose = manager.read_choose(0, 5);
	if (choose == 0 || choose == -1) {
		manager.show_back();
		return 0;
	}

	return choose;
}

//Select query method 
int query_ch() {
	if (!manager.isEmpty())
		return 0;
	int choose;
	cout << "=======================================================" << endl;
	cout << "----------------Welcome to the query function-----------------------" << endl;
	cout << "    @          [1]Query by name                    @    " << endl;
	cout << "    @          [2]Query by total score                  @    " << endl;
	cout << "    @          [3]Query by math score                @    " << endl;
	cout << "    @          [4]Query by language score                @    " << endl;
	cout << "    @          [5]Query by English score                @    " << endl;
	cout << "    @          [6]Query by student number                    @    " << endl;
	cout << "    @          [0]Return to management system                  @    " << endl;
	cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
	choose = manager.read_choose(0, 6);

	if (choose == 0 || choose == -1) {
		manager.show_back();
		return 0;
	}

	return choose;
}

int menu() {
	int choose;
	cout << "=======================================================" << endl;
	cout << "----------------Welcome to the student achievement management system---------------" << endl;
	cout << "    @          [1]Add grade record                  @    " << endl;
	cout << "    @          [2]Delete grade record                  @    " << endl;
	cout << "    @          [3]Modify grade record                  @    " << endl;
	cout << "    @          [4]Query score record                  @    " << endl;
	cout << "    @          [5]Show all score records              @    " << endl;
	cout << "    @          [6]Rank                      @    " << endl;
	cout << "    @          [0]Exit management system                  @    " << endl;
	cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
	choose = manager.read_choose(0, 6);

	if (choose == -1 || choose == 0) {
		manager.show_back(1);
		cout << "Thanks for using, bye!";
		Sleep(700);
		exit(0);
	}

	system("cls");
	return choose;
}

void start() {
	manager.getAll();		//Get all records first
	while (true) {
		switch (menu()) {
		case 1:
			manager.show_to();
			manager.add();
			break;
		case 2:
			manager.show_to();
			manager.delete_();
			break;
		case 3:
			manager.show_to();
			manager.update();
			break;
		case 4:
			manager.show_to();
			manager.query(query_ch());
			break;
		case 5:
			manager.show_to();
			manager.display(manager.getStudents());
			manager.clear();
			break;
		case 6:
			manager.show_to();
			manager.order(order_ch());
			break;
		}
	}
}

int main() {
	manager.color(3);
	start();

	return 0;
}

---------------Welcome to the student achievement management system ------------ "< endl;
Cout < < "@ [1] add score record @" < < endl;
Cout < < "@ [2] delete the score record @" < < endl;
Cout < < "@ [3] modify score record @" < < endl;
Cout < < "@ [4] query score record @" < < endl;
Cout < < "@ [5] display all score records @" < < endl;
Cout < < "@ [6] ranking @" < < endl;
Cout < < "@ [0] exit the management system @" < < endl;
cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
choose = manager.read_choose(0, 6);

if (choose == -1 || choose == 0) {
	manager.show_back(1);
	cout << "Thanks for using, bye!";
	Sleep(700);
	exit(0);
}

system("cls");
return choose;

}

void start() {
manager.getAll(); // Get all records first
while (true) {
switch (menu()) {
case 1:
manager.show_to();
manager.add();
break;
case 2:
manager.show_to();
manager.delete_();
break;
case 3:
manager.show_to();
manager.update();
break;
case 4:
manager.show_to();
manager.query(query_ch());
break;
case 5:
manager.show_to();
manager.display(manager.getStudents());
manager.clear();
break;
case 6:
manager.show_to();
manager.order(order_ch());
break;
}
}
}

int main() {
manager.color(3);
start();

return 0;

}

Keywords: C++ Back-end

Added by mvidberg on Sun, 09 Jan 2022 07:22:43 +0200