【小超嵌入式】基于C++的学生管理系统详细分析

今天,我们探讨一个简单的C++控制台应用程序,它能够实现对学生信息的基本管理功能,包括添加、删除、修改和显示学生数据。
本文旨在向初学者介绍如何使用C++语言开发一个具有基本数据管理功能的小型应用程序。我们不仅会讨论代码的结构和工作原理,还会深入理解每个部分如何协同工作,以及如何处理用户输入和数据存储。此外,我们将重点讲解一些常见的编程模式和技巧,这些对于构建类似应用程序非常关键。

struct Student {
    string name;
    int score;
};

定义了Student结构体:
name字段存储学生的姓名。
score字段存储学生的成绩。

void addStudent(Student students[], int& count) {
    Student s;
    cout << "请输入学生姓名:";
    cin >> s.name;
    cout << "请输入学生成绩:";
    cin >> s.score;
    students[count++] = s;
}

定义一个函数addStudent,其功能是在一个Student类型的数组中添加一个新的学生记录。下面是对这段代码的逐行分析:

void addStudent(Student students[], int& count) {

定义函数addStudent,它接收两个参数:

  • 第一个参数是一个Student类型的数组指针students[]。这个数组用来存储学生的信息。
  • 第二个参数是一个整型引用int& count。这个引用是用来追踪数组中已填充的学生记录数量的。通过引用传递可以确保在函数内部修改count的值时,这些改变能够反映到函数外部。
Student s;

声明一个局部变量s,类型为Students将被用来临时存储从用户输入中收集的学生信息。

cout << "请输入学生姓名:";
cin >> s.name;

输出一个提示消息,要求用户输入学生的姓名,并且使用cin流从标准输入读取数据,将其存储到s.name中。

cout << "请输入学生成绩:";
cin >> s.score;

同样输出一个提示消息,要求用户输入学生的成绩,然后读取输入并存储到s.score中。

students[count++] = s;

将临时Student对象s的数据复制到students数组中的第count个位置。注意,数组的索引是从0开始的,所以students[count]实际上是指向下一个可用位置的。
count++意味着在赋值后,count的值增加1,这反映了数组中又多了一个元素。
当函数addStudent执行完毕后,students数组中就多了一个包含新学生信息的元素,并且count变量更新了新的数组长度。
注意:这段代码假设了Student结构体至少包含namescore成员,并且students数组有足够的空间来存储新的学生信息,否则count++students[count++]的操作可能导致数组越界错误。在实际应用中,应当确保students数组的大小足够大,或者在添加学生之前检查数组是否已满。

void deleteStudent(Student students[], int& count, string name) {
    for (int i = 0; i < count; i++) {
        if (students[i].name == name) {
            for (int j = i; j < count - 1; j++) {
                students[j] = students[j + 1];
            }
            count--;
            break;
        }
    }
}

定义一个函数deleteStudent,用于从一个Student类型的数组中删除具有特定名字的学生记录。下面是详细的代码解释:

void deleteStudent(Student students[], int& count, string name) {

函数deleteStudent接收三个参数:

  • 第一个参数students[]是一个指向Student类型数组的指针,该数组存储了所有学生的信息。
  • 第二个参数int& count是一个整数引用,表示数组中当前有效学生记录的数量。
  • 第三个参数string name是要删除的学生的名字。
for (int i = 0; i < count; i++) {

遍历整个数组的循环,从第一个元素(索引为0)开始,直到count(不包括count,因为数组的索引是从0开始的)。

if (students[i].name == name) {
	for (int j = i; j < count - 1; j++) {
               students[j] = students[j + 1];
           }

如果找到了匹配的学生,那么接下来的这个内部循环会将students数组中位于j+1位置的元素覆盖到j位置的元素上,从而实现删除的效果。这是因为数组并没有真正的“删除”操作,我们只能通过覆盖来模拟删除。这个过程会持续到count-1,即最后一个有效元素的位置。

 count--;

在覆盖操作完成后,count的值减1,这样数组的有效长度就减少了1,表示一个学生已经被“删除”。

break;

break语句用于跳出最内层的循环,因为我们已经找到了要删除的学生并完成了删除操作,没有必要再继续查找。
函数完成循环,如果没有找到要删除的学生,函数将不做任何操作而直接结束。如果找到了并删除了学生,那么students数组中的有效学生记录数量会减少1,同时数组的内容会被适当调整以移除指定的学生记录。
这种删除方法不会保留数组的原始顺序,而是将被删除元素之后的所有元素向前移动一位。如果需要保持数组中其他学生记录的顺序不变,那么可能需要使用更复杂的算法或数据结构来实现删除操作。此外,当数组接近满时,频繁的删除操作可能会导致效率降低,因为每次删除都需要重新排列数组中的元素。

void modifyStudent(Student students[], int count, string name) {
    for (int i = 0; i < count; i++) {
        if (students[i].name == name) {
            cout << "请输入新的成绩:";
            cin >> students[i].score;
            break;
        }
    }
}

定义一个modifyStudent函数,其目的是在给定的Student类型数组中寻找具有特定名字的学生,并允许修改该学生的成绩。下面是详细的代码分析:

void modifyStudent(Student students[], int count, string name) {

函数modifyStudent接收三个参数:

  • students[]:一个Student类型的数组,其中包含了学生信息。
  • count:一个整数,表示数组中有效学生记录的数量。
  • name:一个字符串,表示要修改成绩的学生的名字。
for (int i = 0; i < count; i++) {

定义一个循环,用于遍历students数组中的每个学生记录。循环从索引0开始,直到count(不包括count,因为数组的索引是从0开始的)。

if (students[i].name == name) {

在循环体内,这行代码检查当前索引i处的学生名字是否与提供的name参数相匹配。

 cout << "请输入新的成绩:";
 cin >> students[i].score;

如果找到了名字匹配的学生,程序会输出一个提示消息,要求用户输入新的成绩,然后使用cin流从标准输入读取用户输入的成绩,并将其存储到对应学生的score成员中。

 break;

break语句用于终止循环,这意味着一旦找到了名字匹配的学生并修改了其成绩,就不会再继续查找数组中的其他元素。如果没有找到匹配的学生,函数将不会做任何修改,并在循环自然结束后返回。

void displayStudents(Student students[], int count) {
    for (int i = 0; i < count; i++) {
        cout << students[i].name << " " << students[i].score << endl;
    }
}

定义一个displayStudents函数,其功能是打印出所有学生的信息,包括他们的姓名和成绩。下面是详细的解析:

void displayStudents(Student students[], int count) {

函数displayStudents接收两个参数:

  • students[]:这是一个Student类型的数组,其中包含了所有学生的信息。
  • count:这是一个整数,表示数组中有效学生记录的数量。
for (int i = 0; i < count; i++) {

这里定义了一个for循环,用于遍历数组中的每个学生记录。循环从0开始,直到count(不包括count),这是因为数组的索引是从0开始的。

cout << students[i].name << " " << students[i].score << endl;

在循环体内,这行代码使用cout流将当前学生的名字和成绩输出到标准输出设备(通常是屏幕)。students[i].name表示第i个学生的姓名,students[i].score表示该学生的成绩。在姓名和成绩之间输出一个空格,以提供更好的可读性,而endl则表示输出一行后换行,确保每个学生的信息都在新的一行开始。

void saveStudents(Student students[], int count) {
    ofstream file("students.txt");
    for (int i = 0; i < count; i++) {
        file << students[i].name << " " << students[i].score << endl;
    }
    file.close();
}

定义一个saveStudents函数,用于将学生数据从内存中的数组持久化到硬盘上的一个文本文件中。下面是函数的详细解析:

void saveStudents(Student students[], int count) {

此函数接收两个参数:

  • students[] 是一个Student类型的数组,其中存储了学生的信息。
  • count 是一个整数,表示数组中有效学生记录的数量。
ofstream file("students.txt");

这里创建了一个ofstream对象file,并将其打开到名为students.txt的文件。ofstream是C++标准库中的一个类,用于处理文件的输出流。这行代码会尝试创建或打开指定的文件,如果文件不存在,ofstream将自动创建它;如果文件存在,其内容将被清空,以便写入新的数据。

   for (int i = 0; i < count; i++) {
        file << students[i].name << " " << students[i].score << endl;

这是一个循环,它遍历students数组中的每一个学生记录,从索引0开始,直到count(不包括count,因为数组的索引是从0开始的)。在循环体内,使用<<运算符将每个学生的姓名和成绩写入file中,每写入一个学生记录后,使用endl来插入一个换行符,使每个学生的信息出现在文件中的新一行。

 file.close();

循环结束后,file.close()这行代码关闭了文件流file。这是非常重要的,因为关闭文件可以释放操作系统持有的文件资源,同时确保所有缓冲区中的数据都被写入磁盘。如果不关闭文件,可能会导致数据丢失或其他不可预知的问题。

void loadStudents(Student students[], int& count) {
    ifstream file("students.txt");
    if (file.is_open()) {
        while (!file.eof()) {
            Student s;
            file >> s.name >> s.score;
            students[count++] = s;
        }
        file.close();
    }
}

定义一个loadStudents函数,它的目的是从一个名为students.txt的文件中读取学生数据,并将其加载到一个Student类型的数组中。下面是函数的详细解析:

void loadStudents(Student students[], int& count) {

函数接收两个参数:

  • students[]:一个Student类型的数组,用于存储从文件中读取的学生数据。
  • int& count:一个整数引用,用于跟踪数组中当前存储的学生数量。函数结束后,count将反映数组中实际存储的学生记录数量。
ifstream file("students.txt");

这里创建了一个ifstream对象file,用于读取名为students.txt的文件。ifstream是C++标准库中的一个类,用于处理文件的输入流。

if (file.is_open()) {

这行代码检查文件是否成功打开。如果文件未能打开,可能是由于权限问题、文件不存在或其他原因,is_open()函数将返回false,并且if语句块将不会执行。

while (!file.eof()) {
           Student s;
            file >> s.name >> s.score;
           students[count++] = s;
       }

如果文件成功打开,程序将进入while循环。这个循环会一直执行,直到到达文件的末尾(eof,End Of File)。在每次循环迭代中,都会创建一个新的Student对象s,然后尝试从文件中读取学生的名字和成绩,分别存储到s.names.score中。随后,将s对象复制到students数组的当前位置,并递增count的值,以准备存储下一个学生记录。
注意:使用eof来检测文件是否读完并不是一种推荐的做法,因为eof状态标志只有在读取操作失败时才设置。更安全的方法是在读取操作之后立即检查eof,或者使用条件如file >> s.name >> s.score;作为循环条件。

file.close();

在读取完所有数据后,或者在遇到文件读取错误时,file.close()这行代码将关闭文件流,释放相关资源。

int main() {
    Student students[100];
    int count = 0;

    loadStudents(students, count);

    int choice;
    do {
        cout << "1. 添加学生" << endl;
        cout << "2. 删除学生" << endl;
        cout << "3. 修改学生成绩" << endl;
        cout << "4. 显示学生信息" << endl;
        cout << "5. 保存学生信息" << endl;
        cout << "0. 退出" << endl;
        cout << "请选择操作:";
        cin >> choice;

        switch (choice) {
            case 1:
                addStudent(students, count);
                break;
            case 2: {
                string name;
                cout << "请输入要删除的学生姓名:";
                cin >> name;
                deleteStudent(students, count, name);
                break;
            }
            case 3: {
                string name;
                cout << "请输入要修改成绩的学生姓名:";
                cin >> name;
                modifyStudent(students, count, name);
                break;
            }
            case 4:
                displayStudents(students, count);
                break;
            case 5:
                saveStudents(students, count);
                break;
            case 0:
                break;
            default:
                cout << "无效的选择,请重新输入" << endl;
        }
    } while (choice!= 0);

    return 0;
}
  1. 初始化
    • 定义一个可以容纳最多100名学生的数组students
    • 初始化一个整型变量count来跟踪数组中实际存储的学生数量。
  2. 加载学生信息
    • 调用loadStudents函数来填充学生数组,通常这个函数会从文件或其他数据源读取学生信息并存入数组中。
  3. 主循环
    • 使用一个do...while循环来持续显示菜单并处理用户输入,直到用户选择退出(输入0)为止。
    • 每次循环开始时,都会显示一个菜单,列出可以执行的操作选项。
  4. 处理用户选择
    • 用户通过输入数字来选择要执行的操作。
    • 使用switch语句来根据用户的输入调用相应的函数。
    • 每个case都对应着一个具体的功能,如添加、删除、修改学生信息或显示所有学生信息等。
    • 如果用户输入的是0,则跳出循环,结束程序。
  5. 功能函数调用
    • addStudent:用于添加新学生。
    • deleteStudent:根据提供的学生姓名删除学生。
    • modifyStudent:允许修改某个学生的成绩。
    • displayStudents:显示所有学生的信息。
    • saveStudents:保存当前学生信息,可能涉及将数据写回文件或数据库。
  6. 退出条件
    • 当用户输入0时,do...while循环结束,程序随之终止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小超电子笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值