C语言课程设计:学生成绩管理系统
项目概述
本项目旨在使用C语言开发一个基于命令行的学生成绩管理系统,该系统将实现对学生信息的增、删、改、查等基本操作,并能进行简单的成绩统计与分析,通过本课程设计,可以巩固和深化对C语言核心知识(如结构体、数组、指针、文件I/O等)的理解,并掌握模块化程序设计的基本思想。

(图片来源网络,侵删)
功能需求分析
系统应具备以下核心功能:
- 录入学生信息:能够从键盘输入一个或多个学生的学号、姓名、多门课程的成绩(如C语言、高等数学、英语)。
- 显示所有学生信息:以表格形式清晰展示所有已录入学生的完整信息。
- 查询学生信息:可以通过学号或姓名查询特定学生的信息,并显示。
- 修改学生信息:根据学号找到学生,并可以修改其姓名或任意一门课程的成绩。
- 删除学生信息:根据学号找到学生,并将其信息从系统中移除。
- 统计与分析:
- 计算每个学生的总分和平均分。
- 计算每门课程的平均分、最高分和最低分。
- (可选)按总分或平均分对学生进行排序。
- 数据持久化:将所有学生信息保存到文件中,程序启动时能从文件中加载数据,退出时自动保存数据,确保信息不丢失。
系统设计
数据结构设计
为了存储学生信息,我们使用struct(结构体)来定义一个学生模型。
#define MAX_NAME_LEN 20
#define MAX_ID_LEN 15
#define COURSE_NUM 3 // 假设有3门课程
// 课程名称数组,方便显示
const char COURSE_NAMES[COURSE_NUM][20] = {"C语言", "高等数学", "英语"};
typedef struct {
char id[MAX_ID_LEN]; // 学号
char name[MAX_NAME_LEN]; // 姓名
float scores[COURSE_NUM]; // 各科成绩
float total; // 总分
float average; // 平均分
} Student;
模块化设计
为了提高代码的可读性、可维护性和复用性,我们将不同功能的代码封装到不同的函数中,形成独立的模块。
| 模块名称 | 功能描述 | 主要函数 |
|---|---|---|
| 主菜单模块 | 显示系统主菜单,接收用户选择,调用相应功能函数 | showMenu() |
| 数据管理模块 | 负责文件的读写,实现数据的持久化 | saveToFile(), loadFromFile() |
| 学生信息录入模块 | 处理学生信息的输入 | addStudent(), inputStudentInfo() |
| 学生信息显示模块 | 格式化输出学生信息列表 | displayAllStudents() |
| 学生信息查询模块 | 按学号或姓名查询学生 | queryStudent() |
| 学生信息修改模块 | 根据学号定位并修改学生信息 | modifyStudent() |
| 学生信息删除模块 | 根据学号定位并删除学生信息 | deleteStudent() |
| 成绩统计模块 | 计算并显示各类统计数据 | calculateStatistics(), sortStudents() |
文件设计
使用二进制文件(.dat)来存储学生数据,相比文本文件,读写速度更快,且格式不易出错。

(图片来源网络,侵删)
- 文件名:
students.dat - :一个
Student结构体数组。
核心代码实现
下面是完整的项目代码,包含了详细的注释。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),Windows平台下按任意键继续
// --- 常量定义 ---
#define MAX_STUDENTS 100 // 最大学生数量
#define MAX_NAME_LEN 20
#define MAX_ID_LEN 15
#define COURSE_NUM 3
#define FILENAME "students.dat"
// 课程名称
const char COURSE_NAMES[COURSE_NUM][20] = {"C语言", "高等数学", "英语"};
// --- 学生结构体 ---
typedef struct {
char id[MAX_ID_LEN];
char name[MAX_NAME_LEN];
float scores[COURSE_NUM];
float total;
float average;
} Student;
// --- 全局变量 ---
Student students[MAX_STUDENTS]; // 学生数组
int student_count = 0; // 当前学生数量
// --- 函数声明 ---
void showMenu();
void loadFromFile();
void saveToFile();
void addStudent();
void displayAllStudents();
void queryStudent();
void modifyStudent();
void deleteStudent();
void calculateStatistics();
void sortStudents();
void inputStudentInfo(Student *s);
void clearInputBuffer();
// --- 主函数 ---
int main() {
loadFromFile(); // 程序启动时加载数据
int choice;
do {
showMenu();
printf("请输入您的选择: ");
scanf("%d", &choice);
clearInputBuffer(); // 清除输入缓冲区中的换行符
switch (choice) {
case 1: addStudent(); break;
case 2: displayAllStudents(); break;
case 3: queryStudent(); break;
case 4: modifyStudent(); break;
case 5: deleteStudent(); break;
case 6: calculateStatistics(); break;
case 7: sortStudents(); break;
case 0:
saveToFile();
printf("感谢使用,数据已保存,再见!\n");
break;
default:
printf("无效的选择,请重新输入!\n");
break;
}
if (choice != 0) {
printf("\n按任意键返回主菜单...");
getch(); // 等待用户按键
}
} while (choice != 0);
return 0;
}
// --- 显示主菜单 ---
void showMenu() {
system("cls"); // Windows下清屏,Linux/macOS用 system("clear");
printf("========================================\n");
printf("= 学生成绩管理系统 v1.0 =\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("= 0. 退出系统 =\n");
printf("========================================\n");
}
// --- 从文件加载数据 ---
void loadFromFile() {
FILE *fp = fopen(FILENAME, "rb");
if (fp == NULL) {
// 文件不存在,是第一次运行,正常情况
return;
}
// 读取学生数量
fread(&student_count, sizeof(int), 1, fp);
// 读取学生数组
fread(students, sizeof(Student), student_count, fp);
fclose(fp);
printf("成功从 %s 加载了 %d 条学生记录,\n", FILENAME, student_count);
}
// --- 保存数据到文件 ---
void saveToFile() {
FILE *fp = fopen(FILENAME, "wb");
if (fp == NULL) {
printf("错误:无法打开文件 %s 进行写入!\n", FILENAME);
return;
}
// 写入学生数量
fwrite(&student_count, sizeof(int), 1, fp);
// 写入学生数组
fwrite(students, sizeof(Student), student_count, fp);
fclose(fp);
}
// --- 录入学生信息 ---
void addStudent() {
if (student_count >= MAX_STUDENTS) {
printf("学生数量已达上限,无法继续添加!\n");
return;
}
printf("\n--- 录入学生信息 ---\n");
inputStudentInfo(&students[student_count]);
student_count++;
printf("学生信息添加成功!\n");
}
// --- 输入单个学生信息 ---
void inputStudentInfo(Student *s) {
printf("请输入学号: ");
scanf("%s", s->id);
clearInputBuffer();
printf("请输入姓名: ");
scanf("%s", s->name);
clearInputBuffer();
s->total = 0;
for (int i = 0; i < COURSE_NUM; i++) {
printf("请输入%s成绩: ", COURSE_NAMES[i]);
scanf("%f", &s->scores[i]);
s->total += s->scores[i];
}
s->average = s->total / COURSE_NUM;
}
// --- 显示所有学生信息 ---
void displayAllStudents() {
if (student_count == 0) {
printf("\n当前没有任何学生信息!\n");
return;
}
printf("\n--- 所有学生信息 ---\n");
printf("---------------------------------------------------------------------------------\n");
printf("学号\t\t姓名\t\t");
for (int i = 0; i < COURSE_NUM; i++) {
printf("%s\t\t", COURSE_NAMES[i]);
}
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 < COURSE_NUM; 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);
}
// --- 查询学生信息 ---
void queryStudent() {
if (student_count == 0) {
printf("\n当前没有任何学生信息!\n");
return;
}
int choice;
char keyword[MAX_ID_LEN];
printf("\n--- 查询学生信息 ---\n");
printf("1. 按学号查询\n");
printf("2. 按姓名查询\n");
printf("请选择查询方式: ");
scanf("%d", &choice);
clearInputBuffer();
printf("请输入查询关键词: ");
scanf("%s", keyword);
clearInputBuffer();
int found = 0;
for (int i = 0; i < student_count; i++) {
if ((choice == 1 && strcmp(students[i].id, keyword) == 0) ||
(choice == 2 && strcmp(students[i].name, keyword) == 0)) {
printf("\n查询结果:\n");
printf("学号: %s, 姓名: %s\n", students[i].id, students[i].name);
printf("成绩: ");
for (int j = 0; j < COURSE_NUM; j++) {
printf("%s: %.2f ", COURSE_NAMES[j], students[i].scores[j]);
}
printf("\n总分: %.2f, 平均分: %.2f\n", students[i].total, students[i].average);
found = 1;
break; // 如果学号唯一,找到后即可退出
}
}
if (!found) {
printf("未找到学号或姓名为 '%s' 的学生,\n", keyword);
}
}
// --- 修改学生信息 ---
void modifyStudent() {
if (student_count == 0) {
printf("\n当前没有任何学生信息!\n");
return;
}
char id[MAX_ID_LEN];
printf("\n--- 修改学生信息 ---\n");
printf("请输入要修改的学生学号: ");
scanf("%s", id);
clearInputBuffer();
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].id, id) == 0) {
printf("已找到学生: %s (%s)\n", students[i].name, students[i].id);
printf("请输入新的信息 (直接回车则保持原样):\n");
char temp_input[50];
printf("姓名 (%s): ", students[i].name);
gets(temp_input);
if (strlen(temp_input) > 0) strcpy(students[i].name, temp_input);
students[i].total = 0;
for (int j = 0; j < COURSE_NUM; j++) {
printf("%s成绩 (%.2f): ", COURSE_NAMES[j], students[i].scores[j]);
gets(temp_input);
if (strlen(temp_input) > 0) {
students[i].scores[j] = atof(temp_input);
}
students[i].total += students[i].scores[j];
}
students[i].average = students[i].total / COURSE_NUM;
printf("学生信息修改成功!\n");
return;
}
}
printf("未找到学号为 '%s' 的学生,\n", id);
}
// --- 删除学生信息 ---
void deleteStudent() {
if (student_count == 0) {
printf("\n当前没有任何学生信息!\n");
return;
}
char id[MAX_ID_LEN];
printf("\n--- 删除学生信息 ---\n");
printf("请输入要删除的学生学号: ");
scanf("%s", id);
clearInputBuffer();
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].id, id) == 0) {
// 将后面的所有学生前移一位,覆盖当前学生
for (int j = i; j < student_count - 1; j++) {
students[j] = students[j + 1];
}
student_count--;
printf("学号为 '%s' 的学生信息已删除,\n", id);
return;
}
}
printf("未找到学号为 '%s' 的学生,\n", id);
}
// --- 成绩统计与分析 ---
void calculateStatistics() {
if (student_count == 0) {
printf("\n当前没有任何学生信息!\n");
return;
}
printf("\n--- 成绩统计与分析 ---\n");
float course_totals[COURSE_NUM] = {0};
float course_max[COURSE_NUM];
float course_min[COURSE_NUM];
// 初始化最高分和最低分
for (int i = 0; i < COURSE_NUM; i++) {
course_max[i] = students[0].scores[i];
course_min[i] = students[0].scores[i];
}
for (int i = 0; i < student_count; i++) {
for (int j = 0; j < COURSE_NUM; j++) {
course_totals[j] += students[i].scores[j];
if (students[i].scores[j] > course_max[j]) {
course_max[j] = students[i].scores[j];
}
if (students[i].scores[j] < course_min[j]) {
course_min[j] = students[i].scores[j];
}
}
}
printf("\n各科成绩统计:\n");
printf("-------------------------------------------------\n");
printf("课程\t\t平均分\t\t最高分\t\t最低分\n");
printf("-------------------------------------------------\n");
for (int i = 0; i < COURSE_NUM; i++) {
float avg = course_totals[i] / student_count;
printf("%s\t\t%.2f\t\t%.2f\t\t%.2f\n", COURSE_NAMES[i], avg, course_max[i], course_min[i]);
}
printf("-------------------------------------------------\n");
}
// --- 学生信息排序 ---
void sortStudents() {
if (student_count == 0) {
printf("\n当前没有任何学生信息!\n");
return;
}
int choice;
printf("\n--- 学生信息排序 ---\n");
printf("1. 按总分降序排序\n");
printf("2. 按平均分降序排序\n");
printf("请选择排序方式: ");
scanf("%d", &choice);
clearInputBuffer();
// 使用简单的冒泡排序
for (int i = 0; i < student_count - 1; i++) {
for (int j = 0; j < student_count - 1 - i; j++) {
float compare_value1 = (choice == 1) ? students[j].total : students[j].average;
float compare_value2 = (choice == 1) ? students[j+1].total : students[j+1].average;
if (compare_value1 < compare_value2) {
Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
printf("排序完成!\n");
displayAllStudents(); // 排序后立即显示
}
// --- 清除输入缓冲区 ---
void clearInputBuffer() {
while (getchar() != '\n');
}
编译与运行指南
- 环境:支持C语言的编译器,如GCC (Linux/macOS) 或 MinGW/Visual Studio (Windows)。
- 保存代码:将以上代码保存为
grade_management.c文件。 - 编译:
- GCC (Linux/macOS/Windows with MinGW):
gcc grade_management.c -o grade_management
- Visual Studio:
- 创建一个新的 "C++ 空项目"(虽然代码是C,但VS兼容性很好)。
- 将
grade_management.c添加到项目中。 - 选择 "生成" -> "生成解决方案"。
- GCC (Linux/macOS/Windows with MinGW):
- 运行:
- 命令行:
./grade_management # Linux/macOS grade_management.exe # Windows
- Visual Studio: 按
F5或点击 "本地Windows调试器" 运行。
- 命令行:
功能扩展建议
如果觉得基本功能已经掌握,可以尝试以下扩展来提升项目难度和完整性:
- 密码登录系统:增加一个简单的用户名和密码验证功能。
- 更复杂的查询:支持按分数段查询(如查询C语言成绩在80-90分之间的所有学生)。
- 动态内存分配:使用
malloc和realloc动态分配内存,替代固定大小的students数组,实现学生数量无上限。 - 图形用户界面:使用图形库(如EasyX, GTK, Qt)将命令行界面改为图形界面,提升用户体验。
- 多文件结构:将代码拆分到
.h(头文件) 和.c(源文件) 中,student.h,main.c,file_io.c等,这是大型项目的标准做法。 - 数据备份与恢复:增加数据备份功能和从备份文件恢复数据的功能。
这个项目涵盖了C语言的大部分核心知识点,是一个非常好的课程设计选择,祝你项目顺利!

(图片来源网络,侵删)
