这是我参加2024年大学生信息系统创新大赛——C++编程挑战赛决赛
的作品,由于时间和技术有限(当时正是大一期末
),没有采用数据库
存储数据,代以文本文件
。最后获得三等奖
main.cpp
#include <iostream>
#include <string>
#include <cstdlib> // 包含 exit() 退出函数
#include "Login.h"
#include "Student.h"
using namespace std;
// 考虑到重复包含头文件的问题,所以我将ManagerModule和StudentModule类的定义移到了main.cpp文件中
int status; // 因为用户是本程序的核心,所以我直接将用户的几个身份标识定义为全局变量
string current_username;
string current_password;
string file_name = "students_data.txt"; // 数据来源
void change_password()
{
string old_password,new_password,confirm_password;
while (true) {
cout << "请输入原始密码(键入`quit`退出):";
cin >> old_password;
if (old_password == "quit") {
cout << "成功退出" << endl;
break;
} else if (old_password == current_password) {
cout << "请输入新密码:";
cin >> new_password;
cout << "请确认新密码:";
cin >> confirm_password;
if (confirm_password == new_password) {
cout << "密码修改成功!请妥善保管" << endl;
current_password = new_password;
break;
}
else {
cout << "前后两次密码不一样,请重新输入" <<endl;
}
} else {
cout << "密码错误,请重试" << endl;
}
}
}
class ManagerModule
{
public:
ManagerModule() {
stuList.ReadFromFile(file_name); // 从文件中读取数据并存入链表
}
void Manager_Menu() {
while (true)
{
system("chcp 65001 & cls");
cout << "\t\t\t======== 管理员菜单 ========"<<endl<<endl;
cout << "\t\t\t1.学生成绩管理"<<endl;
cout << "\t\t\t2.教师信息管理"<<endl;
cout << "\t\t\t3.专业管理"<<endl;
cout << "\t\t\t4.班级管理"<<endl;
cout << "\t\t\t5.课程管理"<<endl;
cout << "\t\t\t6.公告信息管理"<<endl;
cout << "\t\t\t7.系统菜单权限管理"<<endl;
cout << "\t\t\t8.退出程序"<<endl;
cout << "\t请选择你要实现的功能[ ]\b\b";
cin >> root_choice;
function_call(); // 这个函数的实现在第155行
}
}
private:
int root_choice;
StudentList stuList;
void Updata_notice() {
ofstream notice_file("notice.txt",ios::trunc);
if (!notice_file.is_open()) {
cout << "can not open the file" << endl;
return;
}
cout << "请写入新的公告(输入`end`结束):" << endl;
string input;
while (getline(cin,input) && input != "end") {
notice_file << input << endl;
}
notice_file.close();
cout << "已更新公告内容" << endl;
}
void manage_student_score() {
int man_choice;
bool flag = true;
while (flag) {
system("chcp 65001 & cls"); // chcp 65001是为了统一编码为utf-8,从而避免中文乱码
cout << "\t\t\t======== 管理学生成绩 ========" << endl;
cout << "\t\t\t1.增加记录" <<endl;
cout << "\t\t\t2.查找成绩" << endl;
cout << "\t\t\t3.删除记录" << endl;
cout << "\t\t\t4.成绩修改" << endl;
cout << "\t\t\t5.统计分析" << endl;
cout << "\t\t\t6.排序" << endl;
cout << "\t\t\t7.显示所有学生信息" << endl;
cout << "\t\t\t8.保存并退出" << endl<<endl;
cout << "\t\t请选择你要实现的功能[ ]\b\b";
cin >> man_choice;
switch(man_choice) {
case 1: {
Student stu;
cout << "\t\t学号:"; cin >> stu.number;
cout << "\t\t姓名:"; cin >> stu.name;
cout << "\t\t数学成绩:"; cin >> stu.mathScore;
cout << "\t\t物理成绩:"; cin >> stu.physicsScore;
cout << "\t\t英语成绩:"; cin >> stu.englishScore;
stuList.AddRecord(stu);
cout << "成功增加了一条记录记录";
cin.ignore();
cin.get();
break;
}
case 2: {
long long number = 0;
cout << "请输入您要查找学生的学号:";
cin >> number;
stuList.Search(number);
cin.ignore();
cin.get();
break;
}
case 3: {
long long number;
cout << "请输入你想要删除记录的学号:";
cin >> number;
stuList.Search_Delete(number);
cin.ignore(); // 清除换行符
cin.get(); // 在每个 cin.get() 之前添加 cin.ignore(),以清除输入缓冲区中的换行符。这可以避免输入后直接跳过 cin.get() 导致的等待问题。
break;
}
case 4: {
long long number;
cout << "请输入你想要修改记录的学号:";
cin >> number;
stuList.Search_Modify(number);
cin.ignore();
cin.get();
break;
}
case 5: {
int choice=0;
cout << "\t\t\t1.求单科平均成绩" << endl;
cout << "\t\t\t2.求三科总分的平均成绩" << endl;
cout << "\t\t\t3.查看某一科的合格率" << endl;
cout << "\t\t请选择您要实现的功能:[ ]\b\b"; cin >> choice;
if (choice == 1) {
string subject;
cout << "您想要查看哪一科的成绩? "; cin >> subject;
cout << subject << "的平均成绩为:" << stuList.average(subject);
} else if (choice == 2) {
cout << "三科总分的平均成绩:" << stuList.average() << endl;
} else if (choice == 3) {
string subject;
cout << "您想要查看哪一科的合格率? "; cin >> subject;
cout << subject << "的合格率为:" << stuList.returnPassRate(subject);
} else {
cout << "请输入合法的数字" << endl;
}
cin.ignore();
cin.get();
break;
}
case 6: {
stuList.sort_display();
cin.ignore();
cin.get();
break;
}
case 7:
cout << "所有学生的信息如下:" <<endl;
stuList.DisplayLinkedList();
cin.ignore();
cin.get();
break;
case 8:
stuList.WriteToFile(file_name);
flag = false;
break;
}
}
}
void function_call() {
switch(root_choice) {
case 1:
case 2:
manage_student_score();
break;
case 3:
case 4:
case 5:
stuList.DisplayLinkedList();
break;
case 6:
Updata_notice();
break;
case 7:
cout << "暂时无法实现" <<endl;
cin.ignore();
cin.get();
break;
case 8:
exit(0);
break;
default:
cout << "请输入合法的数字" << endl;
cin.ignore();
cin.get(); // 等待用户按下按键
break;
}
}
};
class StudentModule
{
public:
StudentModule() {
stuList.ReadFromFile(file_name);
}
void Student_Menu() {
while (true)
{
system("chcp 65001 & cls");
cout << "\t\t\t======== 学生菜单 ========"<<endl<<endl;
cout << "\t\t\t1.个人中心"<<endl;
cout << "\t\t\t2.修改密码"<<endl;
cout << "\t\t\t3.学生成绩查询"<<endl;
cout << "\t\t\t4.班级排名查询"<<endl;
cout << "\t\t\t5.专业排名查询"<<endl;
cout << "\t\t\t6.公告信息查看"<<endl;
cout << "\t\t\t7.保存并退出" << endl;
cout << "\t请选择你要实现的功能[ ]\b\b";
cin >> stu_choice;
function_call();
}
}
private:
int stu_choice;
StudentList stuList;
void function_call() {
switch(stu_choice) {
case 1:
case 3:
cout << "\t\t个人信息如下" << endl;
stuList.Search(stoll(current_username)); // stoll()的作用是将string转化为long long类型
cin.ignore();
cin.get();
break;
case 2:
change_password();
cin.ignore();
cin.get();
break;
case 4:
case 5:
cout << "您的排名是第" << stuList.ShowRank(stoll(current_username)) << "名";
cin.ignore();
cin.get();
break;
case 6:
stuList.ShowNotice();
cin.ignore();
cin.get();
break;
case 7:
stuList.WriteToFile(file_name);
exit(0);
}
}
};
int main()
{
ManagerModule root_module;
StudentModule stu_module;
Login login;
while (true) {
login.Login_menu();
if (login.CheckCrendential()) {
cout << "登陆成功";
break;
} else {
cout << "用户名或密码错误";
}
cin.ignore();
cin.get();
}
current_username = login.GetUsername();
current_password = login.GetPassword();
if (current_username == "root" && current_password == "root") {
root_module.Manager_Menu();
} else {
stu_module.Student_Menu();
}
return 0;
}
- - -
Student.h
#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <vector>
#include <algorithm> // 用于排序
using namespace std;
class Student
{
public:
long long number; // 学号
string name; // 姓名
float mathScore; // 数学成绩
float physicsScore; // 物理成绩
float englishScore; // 英语成绩
float getTotalScore() const {
return mathScore + physicsScore + englishScore;
}
};
struct Node // 链表的结点
{
Student data; //这里直接使用 Student 类型的数据
struct Node* next;
};
class StudentList
{
public:
StudentList() : head(nullptr) {}
void AddRecord(Student stu) { // 增加记录:要求可以连续增加多条记录
Node *newNode = new Node();
newNode->data = stu;
newNode->next = head; // 因为对刚插入的数据使用的频率一般来说更大,所以采用在头部插入
head = newNode;
}
void DisplayStudent(Node *head) {
cout << "学生姓名:" << head->data.name << "\t\t学号:" << head->data.number <<endl;
cout << "数学成绩:" << head->data.mathScore << "\t\t物理成绩:" << head->data.physicsScore
<< "\t\t英语成绩:" << head->data.englishScore << endl;
}
bool Search(string stu_name) { // 查找:可以根据姓名(或学号)查找某个学生的课程成绩
bool flag = false;
Node *current = head;
while (current != NULL) {
if (current->data.name == stu_name) {
DisplayStudent(current);
flag = true; // 因为姓名有重复的可能性,所以在找到名字后不立即return,而是继续遍历结束
}
current = current->next;
}
return flag;
}
bool Search(long long stu_number) { // 重载函数
Node *current = head;
while (current != NULL) {
if (current->data.number == stu_number) {
DisplayStudent(current);
return true; // 查找到了就返回 ture, 否则返回 false
}
current = current->next;
}
cout << "没有找到学号为" << stu_number << "的学生" << endl;
return false;
}
void DeleteRecord(long long stu_number) {
Node *current = head;
Node *prev = nullptr; // 新增一个指针用于记录当前节点的前一个节点
if (head == nullptr) {
cout << "Error:记录为空" << endl;
return;
}
// 遍历链表查找待删除的节点
while (current != nullptr) {
if (current->data.number == stu_number) {
// 找到待删除节点后,将前一个节点的 next 指针指向待删除节点的下一个节点
if (prev != nullptr) {
prev->next = current->next;
} else {
// 如果 prev 为 nullptr,说明待删除节点是头节点,需要更新 head 指针
head = current->next;
}
// 删除待删除节点,并释放内存
delete current;
cout << "记录已删除" << endl;
return;
}
prev = current;
current = current->next;
}
}
bool Search_Delete(long long stu_number) { // 根据学生学号删除
string confirm; // 删除前,要求用户确认
if (Search(stu_number)) {
cout << "您确定要删除" << stu_number << "这一条记录吗?(t:确定, f:取消)";
cin >> confirm;
} else {
// cout << "没有找到学号为" << stu_number << "的学生"<<endl; 这种输出已存在于Search函数中
return false;
}
if (confirm == "T" || confirm == "t") {
DeleteRecord(stu_number);
return true;
} else if (confirm == "F" || confirm == "f") {
return false;
} else {
cout << "您的输入有误,请重新输入" << endl;
return false;
}
}
bool Search_Modify(long long stu_number) { // 其实Search函数返回stu可能更好,就是可以引用传值
Node *current = head;
while (current != NULL) {
if (current->data.number == stu_number) {
DisplayStudent(current);
cout << "修改后的数学成绩:"; cin >> current->data.mathScore;
cout << "修改后的物理成绩:"; cin >> current->data.physicsScore;
cout << "修改后的英语成绩:"; cin >> current->data.englishScore;
AddRecord(current->data);
return true; // 查找到了就返回 ture, 否则返回 false
}
current = current->next;
}
cout << "没有找到学号为" << stu_number << "的学生" << endl;
return false;
}
void DisplayLinkedList() {
Node *current = head;
while (current != NULL) {
DisplayStudent(current);
cout << endl;
current = current->next;
}
cout << "Display over" <<endl;
}
void ReadFromFile(const string& filename) {
ifstream file(filename);
if (!file.is_open()) {
cout << "无法打开文件" << endl;
return;
}
Student stu;
while (file >> stu.number >> stu.name >> stu.mathScore >> stu.physicsScore >> stu.englishScore)
{
AddRecord(stu);
}
file.close();
}
void WriteToFile(const string& filename) {
ofstream file(filename);
if (!file.is_open()) {
cout << "无法打开文件" << endl;
return;
}
Node *current = head;
while (current != NULL) {
file << current->data.number <<" " << current->data.name <<" "<< current->data.mathScore <<" "<< current->data.physicsScore
<<" " << current->data.englishScore <<" "<< endl;
current = current->next;
}
file.close();
}
// 下面的函数是算法部分了
// 计算总分
float StudentsTotalScore() {
Node *current = head;
float sum = 0.0f;
while (current != NULL) {
sum += current->data.getTotalScore();
current = current->next;
}
return sum;
}
float SingleTotalScore() {
return -1;
}
int StudentsNumber() { // 返回学生人数
Node *current = head;
int count = 0;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
float average(string sub) {
float ave_score = -1.0f;
Node *current = head;
if (sub == "数学") {
while (current != NULL) {
ave_score += current->data.mathScore;
current = current->next;
}
} else if (sub=="物理") {
while (current != NULL) {
ave_score += current->data.physicsScore;
current = current->next;
}
} else if (sub=="英语") {
while (current != NULL) {
ave_score += current->data.englishScore;
current = current->next;
}
} else {
cout << "输入错误";
return ave_score;
}
return ave_score;
}
float average() { // 按要求实现sum函数的重载(既能求单科平均成绩,又能求三科总分的平均成绩)
return StudentsTotalScore() / StudentsNumber();
}
float returnPassRate(string sub) {
float PassRate=-1.0f;
int passNumber=0;
Node *current = head;
if (sub == "数学") {
while (current != NULL) {
if (current->data.mathScore >= 60)
passNumber += 1;
current = current->next;
}
} else if (sub == "物理") {
if (current->data.physicsScore >= 60)
passNumber += 1;
} else if(sub == "英语") {
if (current->data.englishScore >= 60)
passNumber += 1;
} else {
cout << "输入错误";
return PassRate;
}
return passNumber / StudentsNumber();
}
// 排序功能:要求按总分进行排序(从高到低),若总分相同,则按数学排序;若总分和数学相同,则按物理排序;若总分和各科成绩都相同,则按学号排序;
void Students_sort() {
vector<Student> students;
Node *current = head;
// 将学生数据填充到向量中
while (current != nullptr) {
students.push_back(current->data);
current = current->next;
}
// 使用 lambda 函数对学生向量进行排序
sort(students.begin(), students.end(), [](const Student& s1, const Student& s2) {
// 按总分降序排序
if (s1.getTotalScore() != s2.getTotalScore()) {
return s1.getTotalScore() > s2.getTotalScore();
}
// 如果总分相同,按数学成绩降序排序
if (s1.mathScore != s2.mathScore) {
return s1.mathScore > s2.mathScore;
}
// 如果数学成绩相同,按物理成绩降序排序
if (s1.physicsScore != s2.physicsScore) {
return s1.physicsScore > s2.physicsScore;
}
// 如果物理成绩也相同,按学号升序排序
return s1.number < s2.number;
});
}
void sort_display() {
Students_sort();
// 显示排序后的学生信息
Node *current = head;
while (current != NULL) {
cout << "学号: " << current->data.number << ", 姓名: " << current->data.name
<< ", 总分: " << current->data.getTotalScore() << endl;
current = current->next;
}
}
int ShowRank(long long number) { // 显示排名
Students_sort();
int rank=1;
Node *current = head;
while (current != NULL) {
if (current->data.number == number) {
return rank;
} else {
rank++;
}
current = current->next;
}
return 0; // 表示没找到
}
void ShowNotice() {
ifstream infile("notice.txt") ;
if (!infile.is_open()) {
cout << "无法查看公告";
return;
}
string word;
while (infile >> word)
cout << word << " ";
infile.close();
}
private:
Node* head;
};
Login.h
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Login
{
public:
Login() {}
void Login_menu()
{
system("chcp 65001");
system("cls");
cout << "\t\t\t======== 统一身份认证 ========" << endl<<endl;
cout << "\t\t\t请输入您的学号:"; cin >> username;
cout << "\t\t\t请输入您的密码:"; cin >> password;
}
bool CheckCrendential()
{
ifstream file("userdata.txt"); // 这是数据库中的内容
if (!file.is_open()) {
cout <<"无法打开用户数据文件"<<endl;
return false;
}
string line;
string storedUser,storedPassword; // 考虑到重名的可能性,我选择用用户的唯一标识(学号)作为username,而不是姓名
bool foundUser=false,foundPass=false,foundStatus=false; // 这样就需要一些细节上的处理
while (getline(file,line)) {
if (line.find("username:") == 0) {
storedUser = line.substr(10);
foundUser = true;
} else if (line.find("password:") == 0) {
storedPassword = line.substr(10);
foundPass = true;
}
if (foundUser && foundPass) {
if (storedUser == username && storedPassword == password) {
file.close();
return true;
} else {
foundPass = false;
foundUser = false;
foundStatus = false;
storedUser.clear();
storedPassword.clear();
}
}
}
file.close();
return false;
}
string GetUsername() {
return username;
}
string GetPassword() {
return password;
}
private:
string username;
string password;
};
notice.txt
中南大学是中国湖南省的一所著名综合性大学,坐落在省会长沙市。
中南大学由原中南工业大学、湖南医科大学和长沙铁道学院合并而成,
是国家“211工程”和“985工程”重点支持的高校之一,也是“双一流”建设高校
userdata.txt
username: root
password: root
username: 202332876543
password: 473829
username: 202310987654
password: 984726
username: 202365432190
password: 238456
username: 202398765432
password: 527934
username: 202354321098
password: 682431
username: 202387654321
password: 195384
username: 202321098765
password: 732846
username: 202343210987
password: 984315
username: 202376543210
password: 657483
username: 202390123456
password: 138492
username: 202356789012
password: 586739
username: 202323456789
password: 927534
username: 202398745632
password: 416825
username: 202365412378
password: 378952
username: 202332198765
password: 512943
username: 202387651234
password: 863791
username: 202354329876
password: 293847
username: 202312345678
password: 785412
username: 202345678901
password: 629578
username: 202378901234
password: 943621
username: 202390876543
password: 837492
username: 202354678912
password: 249186
username: 202323451234
password: 573819
username: 202387659876
password: 692714
username: 202354327890
password: 785349
username: 202312348765
password: 429375
username: 202345671234
password: 837215
username: 202378905432
password: 561928
username: 202390874563
password: 483629
username: 202356783210
password: 975341
username: 202321095678
password: 638492
username: 202387652345
password: 419283
username: 202354326789
password: 837592
username: 202310983210
password: 296483
username: 202343217890
password: 543829
username: 202376549876
password: 782643
username: 202398762345
password: 493721
username: 202356784321
password: 758421
students_data.txt
202332876543 公子 23 92 85
202310987654 刻晴 55 32 78
202365432190 迪卢克 99 20 81
202398765432 荧 67 45 90
202354321098 香菱 78 89 56
202387654321 雷电将军 34 67 20
202321098765 莫娜 95 76 43
202343210987 丽莎 88 54 32
202376543210 琴 65 90 78
202390123456 诺艾尔 45 87 65
202356789012 重云 74 35 99
202323456789 凝光 56 78 23
202398745632 阿贝多 89 67 45
202365412378 温迪 34 56 89
202332198765 魈 90 23 76
202387651234 宵宫 67 98 54
202354329876 七七 45 78 32
202312345678 荒泷一斗 87 65 90
202345678901 行秋 76 34 89
202378901234 砂糖 56 97 45
202390876543 可莉 65 89 76
202354678912 菲谢尔 34 78 21
202323451234 申鹤 98 67 54
202387659876 北斗 45 36 98
202354327890 辛焱 87 90 65
202312348765 云堇 76 54 89
202345671234 烟绯 67 89 45
202378905432 珊瑚宫心海 56 34 97
202390874563 九条裟罗 98 76 54
202356783210 雷电真 45 67 89
202321095678 巴巴托斯 87 98 76
202387652345 早柚 78 56 45
202354326789 罗莎莉亚 67 89 34
202310983210 鹿野院平藏 56 78 90
202343217890 托马 99 67 54
202376549876 雷电芽衣 45 89 76
202398762345 神里绫华 87 56 98
202356784321 神里绫人 78 97 65
最后编译main.cpp文件
简要介绍:
- 管理员菜单
- 进入管理员菜单
- 选择【1】会进入二级菜单(学生成绩管理)显示如下:
二级菜单(在这个菜单下,可以完成对学生成绩的基本操作)
示例:
其他功能不再展示。Over
说明:
- 这个系统并不完善,没有采用数据库而是文本,但是仍然可以做到实时更新,以及增删查改的操作
- 有些功能并未实现
- 此系统分为三种用户(管理员,教师,学生),在
userdata.txt
中存储这这些信息,但并未标识身份,可以加入一个user_level
来标识身份。 - 以后有时间可能会继续完善这个系统,也欢迎朋友们指正某些不合理的设计