这个系统将使用结构体来存储学生信息,使用文件来实现数据的持久化存储(即程序关闭后数据不会丢失),整个程序采用模块化设计,将不同功能封装成独立的函数,使代码结构清晰,易于维护和扩展。

(图片来源网络,侵删)
功能需求分析
一个功能完善的学生成绩管理系统应具备以下功能:
- 录入学生信息:可以添加新的学生记录,包括学号、姓名、各科成绩。
- 显示所有学生信息:以表格形式清晰地展示所有学生的数据。
- 查询学生信息:
- 按学号查询
- 按姓名查询
- 修改学生信息:根据学号找到学生并修改其信息。
- 删除学生信息:根据学号删除指定的学生记录。
- 统计功能:
- 计算每个学生的总分和平均分。
- 计算每门课程的平均分。
- 找出总分最高和最低的学生。
- 排序功能:可以按总分或单科成绩对学生进行排序(升序/降序)。
- 数据保存与加载:
- 将所有学生信息保存到文件中(如
students.dat)。 - 程序启动时自动从文件中加载已有数据。
- 将所有学生信息保存到文件中(如
- 退出系统:保存数据并安全退出。
数据结构设计
为了存储学生信息,我们定义一个结构体 Student:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),在Windows下按任意键继续
// 定义学生结构体
#define MAX_NAME_LEN 50
#define MAX_ID_LEN 20
#define COURSE_NUM 3 // 假设有3门课程
typedef struct {
char id[MAX_ID_LEN]; // 学号
char name[MAX_NAME_LEN]; // 姓名
float scores[COURSE_NUM]; // 各科成绩
float total; // 总分
float average; // 平均分
} Student;
核心代码实现
下面是完整的C语言源代码,我将它分模块进行解释。
1 头文件和全局变量
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),在Windows下按任意键继续
// --- 数据结构定义 ---
#define MAX_NAME_LEN 50
#define MAX_ID_LEN 20
#define COURSE_NUM 3 // 假设有3门课程:数学、英语、C语言
#define FILENAME "students.dat"
typedef struct {
char id[MAX_ID_LEN];
char name[MAX_NAME_LEN];
float scores[COURSE_NUM];
float total;
float average;
} Student;
// 全局变量:学生数组和学生数量
Student students[1000]; // 假设最多存储1000名学生
int student_count = 0;
2 功能函数声明
// 函数声明 void show_menu(); void load_data(); void save_data(); void add_student(); void display_all(); void search_student(); void modify_student(); void delete_student(); void calculate_statistics(); void sort_students(); void calculate_student_totals();
3 主函数
int main() {
load_data(); // 程序启动时加载数据
int choice;
while (1) {
show_menu();
printf("请输入您的选择: ");
scanf("%d", &choice);
switch (choice) {
case 1: add_student(); break;
case 2: display_all(); break;
case 3: search_student(); break;
case 4: modify_student(); break;
case 5: delete_student(); break;
case 6: calculate_statistics(); break;
case 7: sort_students(); break;
case 0:
save_data();
printf("感谢使用,数据已保存,再见!\n");
exit(0);
default:
printf("无效的输入,请重新选择!\n");
system("pause"); // 按任意键继续
}
system("cls"); // 清屏,Windows系统有效
}
return 0;
}
4 菜单显示
void show_menu() {
printf("\n\n\n");
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");
}
5 文件操作 (数据持久化)
// 从文件加载数据
void load_data() {
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("成功从文件加载 %d 条学生记录,\n", student_count);
system("pause");
}
// 保存数据到文件
void save_data() {
FILE *fp = fopen(FILENAME, "wb");
if (fp == NULL) {
printf("错误:无法打开文件进行保存!\n");
return;
}
// 先写入学生数量
fwrite(&student_count, sizeof(int), 1, fp);
// 再写入所有学生数据
fwrite(students, sizeof(Student), student_count, fp);
fclose(fp);
}
6 核心功能实现
// 计算单个学生的总分和平均分
void calculate_student_totals(Student *s) {
s->total = 0;
for (int i = 0; i < COURSE_NUM; i++) {
s->total += s->scores[i];
}
s->average = s->total / COURSE_NUM;
}
// 1. 录入学生信息
void add_student() {
if (student_count >= 1000) {
printf("学生数量已达上限,无法添加!\n");
system("pause");
return;
}
Student s;
printf("请输入学号: ");
scanf("%s", s.id);
printf("请输入姓名: ");
scanf("%s", s.name);
printf("请输入数学成绩: ");
scanf("%f", &s.scores[0]);
printf("请输入英语成绩: ");
scanf("%f", &s.scores[1]);
printf("请输入C语言成绩: ");
scanf("%f", &s.scores[2]);
calculate_student_totals(&s);
students[student_count++] = s;
printf("学生信息添加成功!\n");
system("pause");
}
// 2. 显示所有学生信息
void display_all() {
if (student_count == 0) {
printf("系统中没有学生信息!\n");
system("pause");
return;
}
printf("\n%-15s %-20s %-10s %-10s %-10s %-10s %-10s\n",
"学号", "姓名", "数学", "英语", "C语言", "总分", "平均分");
printf("-----------------------------------------------------------------\n");
for (int i = 0; i < student_count; i++) {
printf("%-15s %-20s ", students[i].id, students[i].name);
for (int j = 0; j < COURSE_NUM; j++) {
printf("%-10.1f ", students[i].scores[j]);
}
printf("%-10.1f %-10.1f\n", students[i].total, students[i].average);
}
system("pause");
}
// 3. 查询学生信息 (按学号/姓名)
void search_student() {
if (student_count == 0) {
printf("系统中没有学生信息!\n");
system("pause");
return;
}
int choice;
printf("1. 按学号查询\n2. 按姓名查询\n请选择查询方式: ");
scanf("%d", &choice);
char keyword[MAX_ID_LEN];
int found = 0;
if (choice == 1) {
printf("请输入要查询的学号: ");
scanf("%s", keyword);
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].id, keyword) == 0) {
printf("\n%-15s %-20s %-10s %-10s %-10s %-10s %-10s\n",
"学号", "姓名", "数学", "英语", "C语言", "总分", "平均分");
printf("-----------------------------------------------------------------\n");
printf("%-15s %-20s ", students[i].id, students[i].name);
for (int j = 0; j < COURSE_NUM; j++) {
printf("%-10.1f ", students[i].scores[j]);
}
printf("%-10.1f %-10.1f\n", students[i].total, students[i].average);
found = 1;
break;
}
}
} else if (choice == 2) {
printf("请输入要查询的姓名: ");
scanf("%s", keyword);
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].name, keyword) == 0) {
printf("\n%-15s %-20s %-10s %-10s %-10s %-10s %-10s\n",
"学号", "姓名", "数学", "英语", "C语言", "总分", "平均分");
printf("-----------------------------------------------------------------\n");
printf("%-15s %-20s ", students[i].id, students[i].name);
for (int j = 0; j < COURSE_NUM; j++) {
printf("%-10.1f ", students[i].scores[j]);
}
printf("%-10.1f %-10.1f\n", students[i].total, students[i].average);
found = 1;
}
}
} else {
printf("无效的选择!\n");
}
if (!found) {
printf("未找到匹配的学生信息!\n");
}
system("pause");
}
// 4. 修改学生信息
void modify_student() {
if (student_count == 0) {
printf("系统中没有学生信息!\n");
system("pause");
return;
}
char id[MAX_ID_LEN];
printf("请输入要修改的学生学号: ");
scanf("%s", id);
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].id, id) == 0) {
printf("找到学生 %s,请输入新的信息:\n", students[i].name);
printf("请输入新的数学成绩 (原: %.1f): ", students[i].scores[0]);
scanf("%f", &students[i].scores[0]);
printf("请输入新的英语成绩 (原: %.1f): ", students[i].scores[1]);
scanf("%f", &students[i].scores[1]);
printf("请输入新的C语言成绩 (原: %.1f): ", students[i].scores[2]);
scanf("%f", &students[i].scores[2]);
calculate_student_totals(&students[i]);
printf("学生信息修改成功!\n");
system("pause");
return;
}
}
printf("未找到学号为 %s 的学生!\n", id);
system("pause");
}
// 5. 删除学生信息
void delete_student() {
if (student_count == 0) {
printf("系统中没有学生信息!\n");
system("pause");
return;
}
char id[MAX_ID_LEN];
printf("请输入要删除的学生学号: ");
scanf("%s", id);
int found_index = -1;
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].id, id) == 0) {
found_index = i;
break;
}
}
if (found_index != -1) {
// 将后面的所有学生前移一位,覆盖掉要删除的学生
for (int i = found_index; i < student_count - 1; i++) {
students[i] = students[i + 1];
}
student_count--;
printf("学号为 %s 的学生信息已删除!\n", id);
} else {
printf("未找到学号为 %s 的学生!\n", id);
}
system("pause");
}
// 6. 统计与分析
void calculate_statistics() {
if (student_count == 0) {
printf("系统中没有学生信息!\n");
system("pause");
return;
}
float course_sums[COURSE_NUM] = {0};
float max_total = students[0].total;
float min_total = students[0].total;
int max_index = 0, min_index = 0;
for (int i = 0; i < student_count; i++) {
for (int j = 0; j < COURSE_NUM; j++) {
course_sums[j] += students[i].scores[j];
}
if (students[i].total > max_total) {
max_total = students[i].total;
max_index = i;
}
if (students[i].total < min_total) {
min_total = students[i].total;
min_index = i;
}
}
printf("\n--- 统计分析结果 ---\n");
printf("1. 各科平均分:\n");
printf(" 数学: %.2f\n", course_sums[0] / student_count);
printf(" 英语: %.2f\n", course_sums[1] / student_count);
printf(" C语言: %.2f\n", course_sums[2] / student_count);
printf("\n2. 总分最高分学生:\n");
printf(" 姓名: %s, 学号: %s, 总分: %.1f\n", students[max_index].name, students[max_index].id, max_total);
printf("\n3. 总分最低分学生:\n");
printf(" 姓名: %s, 学号: %s, 总分: %.1f\n", students[min_index].name, students[min_index].id, min_total);
system("pause");
}
// 7. 成绩排序
void sort_students() {
if (student_count == 0) {
printf("系统中没有学生信息!\n");
system("pause");
return;
}
int choice, order;
printf("1. 按总分排序\n2. 按数学成绩排序\n请选择排序依据: ");
scanf("%d", &choice);
printf("1. 升序\n2. 降序\n请选择排序方式: ");
scanf("%d", &order);
// 使用简单的冒泡排序
for (int i = 0; i < student_count - 1; i++) {
for (int j = 0; j < student_count - 1 - i; j++) {
float key1, key2;
if (choice == 1) { // 按总分
key1 = students[j].total;
key2 = students[j + 1].total;
} else { // 按数学成绩
key1 = students[j].scores[0];
key2 = students[j + 1].scores[0];
}
if ((order == 1 && key1 > key2) || (order == 2 && key1 < key2)) {
// 交换
Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
printf("排序完成!\n");
display_all(); // 排序后直接显示
}
如何编译和运行
- 保存代码:将以上所有代码块合并到一个文件中,
student_management.c。 - 编译:如果你使用的是GCC编译器(在Linux或MinGW/Cygwin中),可以在命令行中运行:
gcc student_management.c -o student_management.exe
(在Linux上,输出文件名可以是
student_management,不需要.exe)
(图片来源网络,侵删) - 运行:
./student_management.exe
- 首次运行:程序会提示“成功从文件加载 0 条学生记录”,因为数据文件
students.dat还不存在,这是正常的。 - 后续运行:当你添加数据并退出后,再次运行程序,它会自动加载上次保存的数据。
可能的改进和扩展
这个版本已经是一个功能完整的系统,但如果你想进一步挑战,可以考虑以下扩展:
- 更健壮的输入验证:检查学号是否重复、成绩是否在0-100之间等。
- 动态内存分配:使用
malloc和realloc来动态分配学生数组内存,而不是使用固定大小的全局数组,这样可以处理任意数量的学生。 - 更复杂的排序:使用
qsort函数(C标准库中的快速排序)来代替冒泡排序,效率更高。 - 图形用户界面:使用像
EasyX(Windows) 或GTK/Qt(跨平台) 这样的库来创建图形界面,使操作更直观。 - 多文件组织:将代码拆分为多个文件(如
main.c,functions.c,functions.h),这是大型项目的标准做法。 - 密码登录:增加一个简单的登录功能,保护系统数据。
- 支持更多课程:通过从文件读取课程信息或让用户动态添加课程名,来增加灵活性。
希望这个详细的实现能帮助你完成你的C语言课程设计!祝你学习顺利!

(图片来源网络,侵删)
