C语言如何高效实现学生成绩管理系统?

99ANYc3cd6
预计阅读时长 39 分钟
位置: 首页 C语言 正文

项目概述

本项目旨在用C语言开发一个控制台(命令行)版的学生成绩管理系统,系统主要功能包括:

c语言程序设计 学生成绩管理
(图片来源网络,侵删)
  1. 录入学生信息:包括学号、姓名、多门课程的成绩。
  2. 显示所有学生信息:以表格形式展示所有学生的数据。
  3. 根据学号查询学生:快速定位并显示特定学生的信息。
  4. 根据学号删除学生:从系统中移除指定学生的记录。
  5. 计算并显示学生总分与平均分:为每个学生和全体学生提供统计信息。
  6. 数据持久化:将学生信息保存到文件中,程序关闭后数据不丢失。

核心设计思想

  1. 数据结构:使用 struct(结构体)来定义一个学生的信息,包括学号、姓名和成绩数组。
  2. 数据存储:使用一个结构体数组 struct Student students[MAX_STUDENTS] 来在内存中存储所有学生信息。
  3. 文件操作:使用C语言的文件I/O函数 (fopen, fread, fwrite, fclose 等) 将内存中的学生数据保存到磁盘文件(如 students.dat),并在程序启动时从文件加载数据。
  4. 模块化设计:将每个功能(如录入、显示、查询等)封装成独立的函数,使代码结构清晰,易于维护和扩展。
  5. 用户交互:通过 switch-case 语句构建一个文本菜单,引导用户选择操作。

完整代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),实现无回显输入,非标准C,但Windows常用
// --- 常量定义 ---
#define MAX_STUDENTS 100
#define MAX_NAME_LEN 50
#define MAX_COURSES 5
#define FILENAME "students.dat"
// --- 学生结构体定义 ---
struct Student {
    char id[20];            // 学号
    char name[MAX_NAME_LEN];// 姓名
    float scores[MAX_COURSES]; // 课程成绩
    float total;            // 总分
    float average;          // 平均分
};
// --- 全局变量 ---
struct Student students[MAX_STUDENTS];
int student_count = 0; // 当前学生数量
// --- 函数声明 ---
void show_menu();
void load_data();
void save_data();
void add_student();
void display_students();
void search_student();
void delete_student();
void calculate_statistics();
// --- 主函数 ---
int main() {
    load_data(); // 程序启动时加载数据
    int choice;
    do {
        show_menu();
        printf("请输入您的选择 (0-6): ");
        scanf("%d", &choice);
        // 清除输入缓冲区,防止后续输入被干扰
        while (getchar() != '\n');
        switch (choice) {
            case 1: add_student(); break;
            case 2: display_students(); break;
            case 3: search_student(); break;
            case 4: delete_student(); break;
            case 5: calculate_statistics(); break;
            case 6: save_data(); printf("数据已保存,程序退出,\n"); break;
            case 0: printf("感谢使用,再见!\n"); break;
            default: printf("无效的输入,请重新输入!\n");
        }
        if (choice != 0) {
            printf("\n按任意键返回主菜单...");
            getch(); // 等待用户按键
        }
    } while (choice != 0);
    return 0;
}
// --- 功能函数实现 ---
// 显示主菜单
void show_menu() {
    system("cls"); // 清屏 (Windows系统), Linux下可用 system("clear");
    printf("========== 学生成绩管理系统 ==========\n");
    printf("||                                  ||\n");
    printf("||      1. 录入学生信息             ||\n");
    printf("||      2. 显示所有学生信息         ||\n");
    printf("||      3. 查询学生信息             ||\n");
    printf("||      4. 删除学生信息             ||\n");
    printf("||      5. 计算统计信息             ||\n");
    printf("||      6. 保存数据并退出           ||\n");
    printf("||      0. 退出 (不保存)            ||\n");
    printf("||                                  ||\n");
    printf("======================================\n");
}
// 从文件加载数据
void load_data() {
    FILE *fp = fopen(FILENAME, "rb");
    if (fp == NULL) {
        // 文件不存在是正常情况(首次运行)
        printf("未找到数据文件,将创建新文件,\n");
        student_count = 0;
        return;
    }
    // 读取学生数量
    fread(&student_count, sizeof(int), 1, fp);
    // 读取所有学生数据
    fread(students, sizeof(struct Student), student_count, fp);
    fclose(fp);
    printf("成功加载 %d 名学生的数据,\n", student_count);
}
// 保存数据到文件
void save_data() {
    FILE *fp = fopen(FILENAME, "wb");
    if (fp == NULL) {
        printf("错误:无法打开文件进行保存!\n");
        return;
    }
    // 先写入学生数量
    fwrite(&student_count, sizeof(int), 1, fp);
    // 再写入所有学生数据
    fwrite(students, sizeof(struct Student), student_count, fp);
    fclose(fp);
}
// 1. 录入学生信息
void add_student() {
    if (student_count >= MAX_STUDENTS) {
        printf("学生数量已达上限,无法继续添加!\n");
        return;
    }
    struct Student s;
    printf("--- 录入第 %d 名学生信息 ---\n", student_count + 1);
    printf("请输入学号: ");
    scanf("%s", s.id);
    printf("请输入姓名: ");
    scanf("%s", s.name);
    s.total = 0;
    printf("请输入 %d 门课程的成绩:\n", MAX_COURSES);
    for (int i = 0; i < MAX_COURSES; i++) {
        printf("  课程 %d: ", i + 1);
        scanf("%f", &s.scores[i]);
        s.total += s.scores[i];
    }
    s.average = s.total / MAX_COURSES;
    students[student_count++] = s;
    printf("学生信息添加成功!\n");
}
// 2. 显示所有学生信息
void display_students() {
    if (student_count == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    printf("--- 所有学生信息 ---\n");
    printf("----------------------------------------------------------------------------------------\n");
    printf("学号\t\t姓名\t\t");
    for(int i = 0; i < MAX_COURSES; i++) printf("课程%d\t\t", i+1);
    printf("总分\t\t平均分\n");
    printf("----------------------------------------------------------------------------------------\n");
    for (int i = 0; i < student_count; i++) {
        printf("%s\t\t%s\t\t", students[i].id, students[i].name);
        for (int j = 0; j < MAX_COURSES; j++) {
            printf("%.2f\t\t", students[i].scores[j]);
        }
        printf("%.2f\t\t%.2f\n", students[i].total, students[i].average);
    }
    printf("----------------------------------------------------------------------------------------\n");
    printf("共 %d 名学生,\n", student_count);
}
// 3. 根据学号查询学生
void search_student() {
    if (student_count == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    char search_id[20];
    printf("请输入要查询的学生学号: ");
    scanf("%s", search_id);
    for (int i = 0; i < student_count; i++) {
        if (strcmp(students[i].id, search_id) == 0) {
            printf("--- 查询结果 ---\n");
            printf("学号: %s\n", students[i].id);
            printf("姓名: %s\n", students[i].name);
            printf("成绩: ");
            for (int j = 0; j < MAX_COURSES; j++) {
                printf("课程%d: %.2f  ", j + 1, students[i].scores[j]);
            }
            printf("\n总分: %.2f\n", students[i].total);
            printf("平均分: %.2f\n", students[i].average);
            return; // 找到后直接返回
        }
    }
    printf("未找到学号为 %s 的学生!\n", search_id);
}
// 4. 根据学号删除学生
void delete_student() {
    if (student_count == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    char delete_id[20];
    printf("请输入要删除的学生学号: ");
    scanf("%s", delete_id);
    for (int i = 0; i < student_count; i++) {
        if (strcmp(students[i].id, delete_id) == 0) {
            // 将后面的所有学生前移一位,覆盖掉当前学生
            for (int j = i; j < student_count - 1; j++) {
                students[j] = students[j + 1];
            }
            student_count--;
            printf("学号为 %s 的学生信息已删除!\n", delete_id);
            return; // 删除后直接返回
        }
    }
    printf("未找到学号为 %s 的学生!\n", delete_id);
}
// 5. 计算统计信息
void calculate_statistics() {
    if (student_count == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    float course_sums[MAX_COURSES] = {0};
    float class_total_sum = 0;
    float class_average_sum = 0;
    for (int i = 0; i < student_count; i++) {
        class_total_sum += students[i].total;
        class_average_sum += students[i].average;
        for (int j = 0; j < MAX_COURSES; j++) {
            course_sums[j] += students[i].scores[j];
        }
    }
    printf("--- 全班统计信息 ---\n");
    printf("班级总人数: %d\n", student_count);
    printf("班级总分平均: %.2f\n", class_total_sum / student_count);
    printf("班级平均分平均: %.2f\n", class_average_sum / student_count);
    printf("\n各课程平均分:\n");
    for (int i = 0; i < MAX_COURSES; i++) {
        printf("  课程 %d 平均分: %.2f\n", i + 1, course_sums[i] / student_count);
    }
}

代码解释

  1. 宏定义

    • MAX_STUDENTS:限制系统最多能管理的学生数量。
    • MAX_NAME_LEN:限制学生姓名的最大长度。
    • MAX_COURSES:定义课程数量,方便修改。
    • FILENAME:指定数据存储的文件名。
  2. struct Student

    定义了学生的完整数据模型,包括基本信息(学号、姓名)和成绩信息(成绩数组、总分、平均分),将总分和平均分也存入结构体,可以避免每次显示时重复计算。

  3. main() 函数

    c语言程序设计 学生成绩管理
    (图片来源网络,侵删)
    • 程序的入口,首先调用 load_data() 从文件加载数据。
    • 使用一个 do-while 循环来持续显示菜单并接收用户输入。
    • switch-case 语句根据用户的选择调用相应的功能函数。
    • getch() 用于暂停程序,让用户看清操作结果后再返回菜单。
  4. 数据持久化函数 (load_data, save_data)

    • load_data():以二进制读取模式 ("rb") 打开文件,如果文件不存在,fopen 返回 NULL,此时我们认为是首次运行,不进行任何操作,如果文件存在,先读取一个 int 类型的数据(即学生数量),然后根据这个数量读取相应数量的 struct Student 结构体数据到 students 数组中。
    • save_data():以二进制写入模式 ("wb") 打开文件("wb" 会覆盖原有文件),先将学生数量写入,然后将整个 students 数组写入文件,这种方式效率很高。
  5. 核心功能函数

    • add_student():提示用户输入学生信息,计算总分和平均分,然后将新学生添加到 students 数组的末尾,并增加 student_count
    • display_students():使用 printf 的格式化输出功能,以美观的表格形式打印所有学生信息。%.2f 用于控制浮点数输出两位小数。
    • search_student() & delete_student():都使用 strcmp 函数来比较学号字符串是否匹配,查找找到后直接显示;删除找到后,通过一个 for 循环将后面的元素前移,实现“删除”效果,并减少 student_count
    • calculate_statistics():遍历所有学生,累加每个学生的总分、平均分以及每门课程的总分,最后计算出全班的各项平均值。

如何编译和运行

  1. 将以上代码保存为一个文件,student_management.c
  2. 打开命令行工具(如 Windows 的 CMD 或 PowerShell,Linux 的 Terminal)。
  3. 使用 GCC 编译器进行编译:
    gcc student_management.c -o student_management.exe
    • 在 Linux/macOS 上,可以去掉 .exe
  4. 运行生成的可执行文件:
    ./student_management.exe

注意:代码中使用了 conio.h 库中的 getch()system("cls"),它们在 Windows 上是兼容的,如果你在 Linux 或 macOS 上编译,需要做如下修改:

  • #include <conio.h> 删除。
  • system("cls"); 替换为 system("clear");
  • getch(); 替换为 printf("按回车键继续...");,然后使用 getchar(); 等待用户输入。

项目扩展思路

这个基础版本已经可以满足课程设计的基本要求,如果你想让它更完善,可以考虑以下扩展:

c语言程序设计 学生成绩管理
(图片来源网络,侵删)
  1. 排序功能

    • 增加一个菜单项“按总分排序”。
    • 使用 qsort 函数(C标准库函数)对学生数组进行排序,你需要自己写一个比较函数,compare_by_total,用于比较两个学生的总分。
  2. 修改学生信息

    • 增加一个菜单项“修改学生信息”。
    • 流程与查询类似:先找到学生,然后允许用户重新输入该学生的姓名和各科成绩,并重新计算其总分和平均分。
  3. 更友好的输入

    • 在录入成绩时,增加输入校验,例如防止输入负数或超过百分比的无效成绩。
    • 使用 fgets 代替 scanf 来读取字符串(如姓名),这样可以避免缓冲区溢出问题,但需要额外处理换行符。
  4. 图形用户界面

    • 如果想挑战更高难度,可以使用第三方库(如 EasyX 在Windows上,或 GTK/Qt 跨平台)来创建图形界面,这将使程序更直观易用。
  5. 动态内存分配

    • 目前使用固定大小的数组,当学生数量接近上限时会有问题,可以改用动态内存分配(malloc, realloc, free),根据实际学生数量动态调整内存,实现更灵活的管理。

这个项目是学习C语言指针、结构体、数组、文件操作等核心知识的绝佳实践,希望这份详细的代码和解释能帮助你顺利完成!

-- 展开阅读全文 --
头像
织梦HTML5模板如何快速搭建响应式网站?
« 上一篇 02-16
dede 如何删除系统模型
下一篇 » 02-16

相关文章

取消
微信二维码
支付宝二维码

目录[+]