系统设计概述
设计目标
- 功能完备:实现学生信息的增、删、改、查、排序和统计等基本功能。
- 结构清晰:采用模块化设计,将不同功能封装到不同的函数中,提高代码的可读性和可维护性。
- 数据持久化:使用文件存储学生数据,确保程序关闭后数据不丢失。
- 用户友好:提供清晰、简洁的菜单界面,方便用户操作。
- 健壮性:对用户的非法输入(如输入非数字、超出范围的选择等)进行简单的处理。
功能模块划分
系统可以划分为以下几个核心模块:

(图片来源网络,侵删)
- 主模块:显示主菜单,并根据用户选择调用其他功能模块。
- 数据结构模块:定义学生信息的结构体。
- 文件操作模块:负责从文件中读取数据(
loadData)和将数据保存到文件(saveData)。 - 录入模块:添加新的学生信息。
- 查询模块:按学号或姓名查询学生信息。
- 修改模块:根据学号找到学生并修改其信息。
- 删除模块:根据学号删除学生信息。
- 显示模块:以表格形式显示所有学生信息。
- 排序模块:按总成绩或单科成绩进行排序。
- 统计模块:计算并显示班级的平均分、最高分、最低分等。
- 退出模块:保存数据并退出程序。
核心数据结构设计
使用 struct 来定义学生信息,并将其封装在一个结构体数组中。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),实现无回显输入
#include <ctype.h> // 用于字符处理
// 定义最大学生数量
#define MAX_STUDENTS 100
// 定义学生信息结构体
typedef struct {
char id[20]; // 学号
char name[50]; // 姓名
float score_math; // 数学成绩
float score_english;// 英语成绩
float score_c; // C语言成绩
float total_score; // 总成绩
float average; // 平均分
} Student;
// 全局变量:学生数组和学生数量
Student students[MAX_STUDENTS];
int student_count = 0;
核心功能函数实现
文件操作
// 从文件加载数据
void loadData() {
FILE *fp = fopen("students.dat", "rb");
if (fp == NULL) {
printf("文件不存在或无法打开,将创建新文件,\n");
return;
}
fread(&student_count, sizeof(int), 1, fp);
fread(students, sizeof(Student), student_count, fp);
fclose(fp);
printf("数据加载成功!共加载 %d 名学生信息,\n", student_count);
}
// 保存数据到文件
void saveData() {
FILE *fp = fopen("students.dat", "wb");
if (fp == NULL) {
printf("错误:无法保存数据到文件!\n");
return;
}
fwrite(&student_count, sizeof(int), 1, fp);
fwrite(students, sizeof(Student), student_count, fp);
fclose(fp);
printf("数据保存成功!\n");
}
录入功能
// 录入学生信息
void addStudent() {
if (student_count >= MAX_STUDENTS) {
printf("学生数量已达上限,无法继续添加!\n");
return;
}
Student s;
printf("请输入学号: ");
scanf("%s", s.id);
printf("请输入姓名: ");
scanf("%s", s.name);
printf("请输入数学成绩: ");
scanf("%f", &s.score_math);
printf("请输入英语成绩: ");
scanf("%f", &s.score_english);
printf("请输入C语言成绩: ");
scanf("%f", &s.score_c);
s.total_score = s.score_math + s.score_english + s.score_c;
s.average = s.total_score / 3.0;
students[student_count++] = s;
printf("学生信息添加成功!\n");
}
查询功能
// 按学号查询
void searchById() {
char id[20];
printf("请输入要查询的学号: ");
scanf("%s", id);
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].id, id) == 0) {
printf("\n--- 查询结果 ---\n");
printf("学号: %s\n", students[i].id);
printf("姓名: %s\n", students[i].name);
printf("数学: %.2f\n", students[i].score_math);
printf("英语: %.2f\n", students[i].score_english);
printf("C语言: %.2f\n", students[i].score_c);
printf("总分: %.2f\n", students[i].total_score);
printf("平均分: %.2f\n", students[i].average);
printf("----------------\n");
return;
}
}
printf("未找到学号为 %s 的学生!\n", id);
}
// 按姓名查询
void searchByName() {
char name[50];
printf("请输入要查询的姓名: ");
scanf("%s", name);
int found = 0;
for (int i = 0; i < student_count; i++) {
if (strcmp(students[i].name, name) == 0) {
found = 1;
printf("\n--- 查询结果 ---\n");
printf("学号: %s\n", students[i].id);
printf("姓名: %s\n", students[i].name);
printf("数学: %.2f\n", students[i].score_math);
printf("英语: %.2f\n", students[i].score_english);
printf("C语言: %.2f\n", students[i].score_c);
printf("总分: %.2f\n", students[i].total_score);
printf("平均分: %.2f\n", students[i].average);
printf("----------------\n");
}
}
if (!found) {
printf("未找到姓名为 %s 的学生!\n", name);
}
}
修改功能
void modifyStudent() {
char id[20];
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);
char temp[50];
printf("新姓名 (%s): ", students[i].name);
getchar(); // 清除输入缓冲区
fgets(temp, sizeof(temp), stdin);
if (strlen(temp) > 1) temp[strlen(temp)-1] = '\0'; // 去掉换行符
if (strlen(temp) > 0) strcpy(students[i].name, temp);
printf("新数学成绩 (%.2f): ", students[i].score_math);
fgets(temp, sizeof(temp), stdin);
if (strlen(temp) > 1 && atof(temp) >= 0) students[i].score_math = atof(temp);
printf("新英语成绩 (%.2f): ", students[i].score_english);
fgets(temp, sizeof(temp), stdin);
if (strlen(temp) > 1 && atof(temp) >= 0) students[i].score_english = atof(temp);
printf("新C语言成绩 (%.2f): ", students[i].score_c);
fgets(temp, sizeof(temp), stdin);
if (strlen(temp) > 1 && atof(temp) >= 0) students[i].score_c = atof(temp);
students[i].total_score = students[i].score_math + students[i].score_english + students[i].score_c;
students[i].average = students[i].total_score / 3.0;
printf("学生信息修改成功!\n");
return;
}
}
printf("未找到学号为 %s 的学生!\n", id);
}
删除功能
void deleteStudent() {
char id[20];
printf("请输入要删除的学生学号: ");
scanf("%s", id);
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 displayAllStudents() {
if (student_count == 0) {
printf("当前没有学生信息!\n");
return;
}
printf("\n%-15s %-10s %-10s %-10s %-10s %-10s %-10s\n",
"学号", "姓名", "数学", "英语", "C语言", "总分", "平均分");
printf("-----------------------------------------------------------------\n");
for (int i = 0; i < student_count; i++) {
printf("%-15s %-10s %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f\n",
students[i].id, students[i].name,
students[i].score_math, students[i].score_english, students[i].score_c,
students[i].total_score, students[i].average);
}
}
排序功能 (使用冒泡排序,易于理解)
// 比较函数,用于按总分降序排序
int compareByTotal(const void *a, const void *b) {
Student *s1 = (Student *)a;
Student *s2 = (Student *)b;
if (s2->total_score > s1->total_score) return 1;
else if (s2->total_score < s1->total_score) return -1;
else return 0;
}
// 按总分排序
void sortByTotalScore() {
qsort(students, student_count, sizeof(Student), compareByTotal);
printf("已按总分从高到低排序!\n");
}
统计功能
void calculateStatistics() {
if (student_count == 0) {
printf("当前没有学生信息,无法统计!\n");
return;
}
float sum_math = 0, sum_eng = 0, sum_c = 0;
float max_math = students[0].score_math, min_math = students[0].score_math;
float max_eng = students[0].score_english, min_eng = students[0].score_english;
float max_c = students[0].score_c, min_c = students[0].score_c;
for (int i = 0; i < student_count; i++) {
sum_math += students[i].score_math;
sum_eng += students[i].score_english;
sum_c += students[i].score_c;
if (students[i].score_math > max_math) max_math = students[i].score_math;
if (students[i].score_math < min_math) min_math = students[i].score_math;
if (students[i].score_english > max_eng) max_eng = students[i].score_english;
if (students[i].score_english < min_eng) min_eng = students[i].score_english;
if (students[i].score_c > max_c) max_c = students[i].score_c;
if (students[i].score_c < min_c) min_c = students[i].score_c;
}
printf("\n--- 成绩统计 ---\n");
printf("科目\t平均分\t最高分\t最低分\n");
printf("--------------------------------\n");
printf("数学\t%.2f\t%.2f\t%.2f\n", sum_math / student_count, max_math, min_math);
printf("英语\t%.2f\t%.2f\t%.2f\n", sum_eng / student_count, max_eng, min_eng);
printf("C语言\t%.2f\t%.2f\t%.2f\n", sum_c / student_count, max_c, min_c);
printf("----------------\n");
}
主菜单与程序入口
// 显示主菜单
void showMenu() {
system("cls"); // Windows下清屏,Linux/macOS用 system("clear");
printf("\n========== 学生成绩管理系统 ==========\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");
printf("请输入您的选择: ");
}
int main() {
// 程序启动时加载数据
loadData();
int choice;
do {
showMenu();
scanf("%d", &choice);
switch (choice) {
case 1: addStudent(); break;
case 2:
printf("--- 查询方式 ---\n1.按学号 2.按姓名\n请选择: ");
int search_choice;
scanf("%d", &search_choice);
if(search_choice == 1) searchById();
else if(search_choice == 2) searchByName();
else printf("无效选择!\n");
break;
case 3: modifyStudent(); break;
case 4: deleteStudent(); break;
case 5: displayAllStudents(); break;
case 6: sortByTotalScore(); break;
case 7: calculateStatistics(); break;
case 0:
saveData();
printf("感谢使用,再见!\n");
break;
default: printf("无效的选择,请重新输入!\n");
}
if (choice != 0) {
printf("\n按任意键返回主菜单...");
getch(); // 等待用户按键
}
} while (choice != 0);
return 0;
}
系统扩展与优化建议
- 密码登录:增加一个简单的密码验证功能,保护数据安全。
- 动态内存分配:使用
malloc和realloc动态分配内存,而不是使用固定大小的数组,这样可以处理任意数量的学生。 - 更健壮的输入验证:对成绩输入进行范围检查(如0-100),防止非法数据。
- 多条件排序:允许用户选择按总分、数学、英语或C语言进行排序。
- 图形用户界面:如果使用支持图形库的编译器(如
graphics.h或第三方库),可以开发一个带有窗口和按钮的GUI版本。 - 数据加密:对于敏感数据,可以在写入文件前进行简单的加密,读取时解密。
- 分页显示:当学生数量很多时,实现分页显示功能,避免屏幕刷得太快。
这个设计方案为你提供了一个坚实的基础,你可以根据这个框架进行编码、测试和进一步的扩展,祝你项目顺利!

(图片来源网络,侵删)
