学生成绩管理系统的C++开发

这是我参加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. 管理员菜单
    在这里插入图片描述
  2. 进入管理员菜单

在这里插入图片描述

  1. 选择【1】会进入二级菜单(学生成绩管理)显示如下:
    在这里插入图片描述
    二级菜单(在这个菜单下,可以完成对学生成绩的基本操作)
    示例:
    在这里插入图片描述
    其他功能不再展示。Over

说明

  • 这个系统并不完善,没有采用数据库而是文本,但是仍然可以做到实时更新,以及增删查改的操作
  • 有些功能并未实现
  • 此系统分为三种用户(管理员,教师,学生),在userdata.txt中存储这这些信息,但并未标识身份,可以加入一个user_level来标识身份。
  • 以后有时间可能会继续完善这个系统,也欢迎朋友们指正某些不合理的设计
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值