c语言程序设计 学生成绩管理系统

99ANYc3cd6
预计阅读时长 47 分钟
位置: 首页 C语言 正文
  1. 录入学生信息:包括学号、姓名、多门课程的成绩。
  2. 显示所有学生信息:以表格形式展示所有学生的数据。
  3. 按学号查询学生:根据学号查找并显示特定学生的信息。
  4. 按学号修改学生信息:找到学生后,可以修改其姓名或成绩。
  5. 按学号删除学生:从系统中移除指定学号的学生。
  6. 计算并显示单科平均分:计算并输出某一门课程的平均成绩。
  7. 计算并显示总分排名:根据学生的总分进行排序并显示排名。
  8. 将数据保存到文件:在程序退出时,将所有学生信息保存到 students.dat 文件中。
  9. 从文件加载数据:在程序启动时,从 students.dat 文件中加载之前保存的学生信息。

程序的整体结构

为了使代码清晰、易于维护,我们将采用模块化设计思想,将不同功能的代码分离到不同的函数中。

c语言程序设计 学生成绩管理系统
(图片来源网络,侵删)
  • 主函数 (main):程序的入口,负责显示菜单、调用其他函数,并控制程序的主循环。
  • 数据结构:使用 struct 来定义学生信息。
  • 功能函数:每个菜单项对应一个功能函数(如 addStudent, displayAll 等)。
  • 辅助函数:一些通用的小函数,如 clearInputBuffer(清空输入缓冲区)。
  • 文件操作:专门用于数据持久化的函数(saveToFile, loadFromFile)。

完整C语言代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),实现“按任意键继续”
// --- 1. 定义学生数据结构 ---
#define MAX_NAME_LEN 50
#define MAX_COURSE_NUM 5 // 假设最多有5门课程
typedef struct {
    char id[20];        // 学号
    char name[MAX_NAME_LEN]; // 姓名
    float scores[MAX_COURSE_NUM]; // 各科成绩
    float total;        // 总分
    float average;      // 平均分
} Student;
// 全局变量:学生数组和学生数量
Student students[1000]; // 假设最多存储1000名学生
int studentCount = 0;
// --- 2. 函数声明 ---
void showMenu();
void addStudent();
void displayAllStudents();
void searchStudent();
void modifyStudent();
void deleteStudent();
void calculateCourseAverage();
void sortByTotalAndDisplay();
void saveToFile();
void loadFromFile();
void clearInputBuffer();
// --- 3. 主函数 ---
int main() {
    loadFromFile(); // 程序启动时,先从文件加载数据
    int choice;
    do {
        showMenu();
        printf("请输入您的选择 (0-8): ");
        scanf("%d", &choice);
        clearInputBuffer(); // 清除输入缓冲区中的换行符
        switch (choice) {
            case 1:
                addStudent();
                break;
            case 2:
                displayAllStudents();
                break;
            case 3:
                searchStudent();
                break;
            case 4:
                modifyStudent();
                break;
            case 5:
                deleteStudent();
                break;
            case 6:
                calculateCourseAverage();
                break;
            case 7:
                sortByTotalAndDisplay();
                break;
            case 8:
                saveToFile();
                printf("数据已保存,程序即将退出,\n");
                break;
            case 0:
                saveToFile(); // 退出前再次保存
                printf("感谢使用,再见!\n");
                break;
            default:
                printf("无效的输入,请重新输入!\n");
                break;
        }
        if (choice != 0) {
            printf("\n按任意键返回主菜单...");
            getch(); // 等待用户按键
        }
    } while (choice != 0);
    return 0;
}
// --- 4. 功能函数实现 ---
// 显示主菜单
void showMenu() {
    system("cls || clear"); // 清屏 (Windows: cls, Linux/macOS: clear)
    printf("========================================\n");
    printf("      欢迎使用学生成绩管理系统\n");
    printf("========================================\n");
    printf("  1. 录入学生信息\n");
    printf("  2. 显示所有学生信息\n");
    printf("  3. 按学号查询学生\n");
    printf("  4. 按学号修改学生信息\n");
    printf("  5. 按学号删除学生\n");
    printf("  6. 计算并显示单科平均分\n");
    printf("  7. 计算并显示总分排名\n");
    printf("  8. 保存数据到文件\n");
    printf("  0. 退出系统\n");
    printf("========================================\n");
}
// 录入学生信息
void addStudent() {
    if (studentCount >= 1000) {
        printf("学生数量已达上限,无法添加!\n");
        return;
    }
    Student s;
    printf("请输入学号: ");
    scanf("%s", s.id);
    clearInputBuffer();
    // 检查学号是否已存在
    for (int i = 0; i < studentCount; i++) {
        if (strcmp(students[i].id, s.id) == 0) {
            printf("错误:该学号已存在!\n");
            return;
        }
    }
    printf("请输入姓名: ");
    fgets(s.name, MAX_NAME_LEN, stdin);
    s.name[strcspn(s.name, "\n")] = '\0'; // 去掉fgets读取的换行符
    s.total = 0;
    printf("请输入 %d 门课程的成绩:\n", MAX_COURSE_NUM);
    for (int i = 0; i < MAX_COURSE_NUM; i++) {
        printf("  课程 %d 成绩: ", i + 1);
        scanf("%f", &s.scores[i]);
        s.total += s.scores[i];
    }
    clearInputBuffer();
    s.average = s.total / MAX_COURSE_NUM;
    students[studentCount++] = s;
    printf("学生信息添加成功!\n");
}
// 显示所有学生信息
void displayAllStudents() {
    if (studentCount == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    printf("\n%-15s %-20s", "学号", "姓名");
    for (int i = 0; i < MAX_COURSE_NUM; i++) {
        printf(" 课程%d ", i + 1);
    }
    printf("  总分   平均分\n");
    printf("-----------------------------------------------------------------\n");
    for (int i = 0; i < studentCount; i++) {
        printf("%-15s %-20s", students[i].id, students[i].name);
        for (int j = 0; j < MAX_COURSE_NUM; j++) {
            printf("%-8.2f", students[i].scores[j]);
        }
        printf("%-8.2f %-8.2f\n", students[i].total, students[i].average);
    }
}
// 按学号查询学生
void searchStudent() {
    if (studentCount == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    char id[20];
    printf("请输入要查询的学号: ");
    scanf("%s", id);
    clearInputBuffer();
    for (int i = 0; i < studentCount; i++) {
        if (strcmp(students[i].id, id) == 0) {
            printf("\n查询到学生信息:\n");
            printf("学号: %s\n", students[i].id);
            printf("姓名: %s\n", students[i].name);
            printf("成绩: ");
            for (int j = 0; j < MAX_COURSE_NUM; 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", id);
}
// 按学号修改学生信息
void modifyStudent() {
    if (studentCount == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    char id[20];
    printf("请输入要修改的学号: ");
    scanf("%s", id);
    clearInputBuffer();
    for (int i = 0; i < studentCount; i++) {
        if (strcmp(students[i].id, id) == 0) {
            printf("找到了学生: %s, %s\n", students[i].id, students[i].name);
            printf("请输入新的姓名 (直接回车保持不变): ");
            char newName[MAX_NAME_LEN];
            fgets(newName, MAX_NAME_LEN, stdin);
            if (strlen(newName) > 1) { // 如果用户输入了内容
                newName[strcspn(newName, "\n")] = '\0';
                strcpy(students[i].name, newName);
            }
            students[i].total = 0; // 重新计算总分和平均分
            printf("请输入新的 %d 门课程成绩:\n", MAX_COURSE_NUM);
            for (int j = 0; j < MAX_COURSE_NUM; j++) {
                printf("  课程 %d 成绩: ", j + 1);
                scanf("%f", &students[i].scores[j]);
                students[i].total += students[i].scores[j];
            }
            clearInputBuffer();
            students[i].average = students[i].total / MAX_COURSE_NUM;
            printf("学生信息修改成功!\n");
            return;
        }
    }
    printf("未找到学号为 %s 的学生!\n", id);
}
// 按学号删除学生
void deleteStudent() {
    if (studentCount == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    char id[20];
    printf("请输入要删除的学号: ");
    scanf("%s", id);
    clearInputBuffer();
    for (int i = 0; i < studentCount; i++) {
        if (strcmp(students[i].id, id) == 0) {
            // 将最后一个学生元素移到被删除的位置
            students[i] = students[studentCount - 1];
            studentCount--;
            printf("学号为 %s 的学生信息已删除!\n", id);
            return;
        }
    }
    printf("未找到学号为 %s 的学生!\n", id);
}
// 计算并显示单科平均分
void calculateCourseAverage() {
    if (studentCount == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    int courseIndex;
    printf("请输入要计算平均分的课程编号 (1-%d): ", MAX_COURSE_NUM);
    scanf("%d", &courseIndex);
    clearInputBuffer();
    if (courseIndex < 1 || courseIndex > MAX_COURSE_NUM) {
        printf("无效的课程编号!\n");
        return;
    }
    float sum = 0;
    for (int i = 0; i < studentCount; i++) {
        sum += students[i].scores[courseIndex - 1];
    }
    float average = sum / studentCount;
    printf("课程 %d 的平均分为: %.2f\n", courseIndex, average);
}
// 计算并显示总分排名
void sortByTotalAndDisplay() {
    if (studentCount == 0) {
        printf("当前没有学生信息!\n");
        return;
    }
    // 创建一个临时数组用于排序,避免修改原始数据顺序
    Student tempStudents[1000];
    memcpy(tempStudents, students, sizeof(Student) * studentCount);
    // 使用冒泡排序(简单易懂,数据量小足够)
    for (int i = 0; i < studentCount - 1; i++) {
        for (int j = 0; j < studentCount - 1 - i; j++) {
            if (tempStudents[j].total < tempStudents[j + 1].total) {
                Student temp = tempStudents[j];
                tempStudents[j] = tempStudents[j + 1];
                tempStudents[j + 1] = temp;
            }
        }
    }
    printf("\n%-5s %-15s %-20s", "排名", "学号", "姓名");
    for (int i = 0; i < MAX_COURSE_NUM; i++) {
        printf(" 课程%d ", i + 1);
    }
    printf("  总分\n");
    printf("-----------------------------------------------------------------\n");
    for (int i = 0; i < studentCount; i++) {
        printf("%-5d %-15s %-20s", i + 1, tempStudents[i].id, tempStudents[i].name);
        for (int j = 0; j < MAX_COURSE_NUM; j++) {
            printf("%-8.2f", tempStudents[i].scores[j]);
        }
        printf("%-8.2f\n", tempStudents[i].total);
    }
}
// 将数据保存到文件
void saveToFile() {
    FILE *fp = fopen("students.dat", "wb"); // "wb" 表示二进制写入
    if (fp == NULL) {
        printf("无法打开文件进行保存!\n");
        return;
    }
    // 先写入学生数量
    fwrite(&studentCount, sizeof(int), 1, fp);
    // 再写入所有学生数据
    fwrite(students, sizeof(Student), studentCount, fp);
    fclose(fp);
    printf("数据已成功保存到 students.dat 文件,\n");
}
// 从文件加载数据
void loadFromFile() {
    FILE *fp = fopen("students.dat", "rb"); // "rb" 表示二进制读取
    if (fp == NULL) {
        // 文件不存在是正常情况(第一次运行)
        return;
    }
    // 先读取学生数量
    fread(&studentCount, sizeof(int), 1, fp);
    // 再读取所有学生数据
    fread(students, sizeof(Student), studentCount, fp);
    fclose(fp);
    printf("数据已成功从 students.dat 文件加载,\n");
}
// 清空输入缓冲区
void clearInputBuffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF); // 读取并丢弃所有字符,直到遇到换行符或文件结束符
}

如何编译和运行

  1. 保存代码:将上面的代码复制并粘贴到一个文本编辑器中,保存为 student_management.c
  2. 编译
    • 如果你使用的是 GCC (在 Linux, macOS 或 Windows 的 MinGW/Cygwin 中),打开终端或命令提示符,进入文件所在目录,然后运行:
      gcc student_management.c -o student_management
    • 如果你使用的是 Visual Studio,创建一个新的C++项目(兼容C),将代码粘贴到主 .c 文件中,然后生成解决方案。
    • 如果你使用的是 Dev-C++,新建一个C源文件,粘贴代码,然后编译运行。
  3. 运行
    • 在GCC环境中,运行生成的可执行文件:
      ./student_management
    • 在其他IDE中,直接点击“运行”按钮即可。

注意system("cls || clear"); 这行代码在Windows上使用 cls 命令清屏,在Linux/macOS上使用 clear 命令,如果你的系统不支持其中一个,程序可能会在切换菜单时多输出几行,这是一个小瑕疵,不影响核心功能。


代码讲解

  1. 数据结构 (Student 结构体)

    • 我们定义了一个 Student 结构体,包含了学号(字符串)、姓名(字符串)、成绩数组(浮点数数组)、总分和平均分,这使得我们可以将一个学生的所有相关信息打包在一起。
    • 使用 #define 定义了常量 MAX_COURSE_NUM,方便以后修改课程数量,而无需在代码中多处修改。
  2. 全局变量

    • students 数组和 studentCount 变量是全局的,这使得在所有函数中都可以访问和修改它们,简化了函数间的数据传递,对于大型项目,全局变量可能带来风险,但对于这种小型管理系统,这是一种简单直接的方法。
  3. 文件操作 (saveToFile, loadFromFile)

    c语言程序设计 学生成绩管理系统
    (图片来源网络,侵删)
    • 我们使用 fopen, fwrite, fread, fclose 等标准C库函数进行文件操作。
    • 模式"wb" (二进制写入) 和 "rb" (二进制读取) 是关键,二进制模式比文本模式更高效,因为它直接将内存中的数据块写入文件,无需进行格式转换。
    • 写入顺序:我们先写入 studentCount,这样在读取时,程序首先就知道要读取多少个 Student 结构体,这是一个非常重要的技巧。
    • 数据持久化loadFromFile()main() 函数的开头被调用,确保每次启动程序时都能加载上次保存的数据。saveToFile() 在用户选择“保存”或“退出”时被调用,确保数据不会丢失。
  4. 输入处理 (clearInputBuffer)

    • scanf 在读取数字或字符串时,会将换行符(\n)留在输入缓冲区中,如果下一个输入是 fgets(如读取姓名),它会直接读取这个换行符,导致用户无法输入姓名。
    • clearInputBuffer 函数专门解决这个问题,它会在每次 scanf 之后被调用,清空缓冲区,确保后续的输入操作正常进行。
  5. 核心算法 (sortByTotalAndDisplay)

    • 排序是一个经典算法,这里我们使用了冒泡排序,因为它实现简单,对于几百个数据量的学生来说,性能完全足够。
    • 为了不改变原始 students 数组的顺序,我们创建了一个临时副本 tempStudents 在其上进行排序,这是一个很好的编程习惯。

这个项目涵盖了C语言中许多核心知识点,包括结构体、数组、函数、文件I/O、指针(间接通过数组索引使用)和基本的算法思想,它是一个非常好的C语言课程设计范例。

c语言程序设计 学生成绩管理系统
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
dede list 指定id
« 上一篇 2025-12-25
c语言中基本的数据类型包括.
下一篇 » 2025-12-25

相关文章

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

目录[+]