- 添加学生信息 (学号、姓名、成绩)
- 显示所有学生信息
- 根据学号查找学生
- 根据学号删除学生
- 根据成绩对学生进行排序
- 将学生信息保存到文件
- 从文件加载学生信息
程序的整体结构
为了使代码清晰、易于维护和扩展,我们将采用模块化的设计思想:

(图片来源网络,侵删)
student.h(头文件): 定义学生结构体、函数原型以及常量。- `student.c (源文件): 实现所有在头文件中声明的函数。
- `main.c (主程序): 包含
main函数,负责显示菜单和调用其他函数。
student.h - 头文件
这个文件定义了程序的核心数据结构和所有函数的声明。
#ifndef STUDENT_H
#define STUDENT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义一个常量,表示最多能存储的学生数量
#define MAX_STUDENTS 100
// 定义学生结构体
typedef struct {
int id; // 学号
char name[50]; // 姓名
float score; // 成绩
} Student;
// 全局变量,用于存储学生数组和当前学生数量
Student students[MAX_STUDENTS];
int student_count = 0;
// 函数原型声明
void display_menu();
void add_student();
void display_all_students();
void find_student_by_id();
void delete_student_by_id();
void sort_students_by_score();
void save_to_file();
void load_from_file();
#endif // STUDENT_H
student.c - 功能实现文件
这个文件包含了所有具体功能的实现逻辑。
#include "student.h"
// 显示主菜单
void display_menu() {
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("请输入您的选择: ");
}
// 添加学生信息
void add_student() {
if (student_count >= MAX_STUDENTS) {
printf("错误:学生数量已达到上限,无法添加!\n");
return;
}
Student new_student;
printf("请输入学号: ");
scanf("%d", &new_student.id);
getchar(); // 消耗掉输入缓冲区中的换行符
// 检查学号是否已存在
for (int i = 0; i < student_count; i++) {
if (students[i].id == new_student.id) {
printf("错误:学号 %d 已存在,添加失败!\n", new_student.id);
return;
}
}
printf("请输入姓名: ");
fgets(new_student.name, sizeof(new_student.name), stdin);
new_student.name[strcspn(new_student.name, "\n")] = 0; // 移除fgets读取的换行符
printf("请输入成绩: ");
scanf("%f", &new_student.score);
students[student_count++] = new_student;
printf("学生信息添加成功!\n");
}
// 显示所有学生信息
void display_all_students() {
if (student_count == 0) {
printf("当前没有学生信息!\n");
return;
}
printf("\n%-10s %-20s %-10s\n", "学号", "姓名", "成绩");
printf("----------------------------------------\n");
for (int i = 0; i < student_count; i++) {
printf("%-10d %-20s %-10.2f\n", students[i].id, students[i].name, students[i].score);
}
}
// 根据学号查找学生
void find_student_by_id() {
int id, found = 0;
printf("请输入要查找的学号: ");
scanf("%d", &id);
for (int i = 0; i < student_count; i++) {
if (students[i].id == id) {
printf("\n找到学生信息:\n");
printf("学号: %d, 姓名: %s, 成绩: %.2f\n", students[i].id, students[i].name, students[i].score);
found = 1;
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生!\n", id);
}
}
// 根据学号删除学生
void delete_student_by_id() {
int id, found = 0;
printf("请输入要删除的学号: ");
scanf("%d", &id);
for (int i = 0; i < student_count; i++) {
if (students[i].id == id) {
found = 1;
// 将后面的所有学生信息前移一位
for (int j = i; j < student_count - 1; j++) {
students[j] = students[j + 1];
}
student_count--; // 学生总数减一
printf("学号为 %d 的学生信息已删除!\n", id);
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生,删除失败!\n", id);
}
}
// 使用冒泡排序根据成绩对学生进行排序(降序)
void sort_students_by_score() {
if (student_count < 2) {
printf("学生数量不足,无需排序!\n");
return;
}
for (int i = 0; i < student_count - 1; i++) {
for (int j = 0; j < student_count - 1 - i; j++) {
if (students[j].score < students[j + 1].score) {
// 交换两个学生的信息
Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
printf("学生信息已按成绩降序排序!\n");
}
// 将学生信息保存到文件
void save_to_file() {
char filename[100];
printf("请输入要保存的文件名 ( students.dat): ");
scanf("%s", filename);
FILE *fp = fopen(filename, "wb"); // "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);
printf("成功将 %d 条学生信息保存到文件 %s!\n", student_count, filename);
}
// 从文件加载学生信息
void load_from_file() {
char filename[100];
printf("请输入要加载的文件名: ");
scanf("%s", filename);
FILE *fp = fopen(filename, "rb"); // "rb" 表示以二进制读取模式打开
if (fp == NULL) {
printf("无法打开文件 %s 进行读取!\n", filename);
return;
}
// 先读取学生数量
fread(&student_count, sizeof(int), 1, fp);
// 检查是否超出最大容量
if (student_count > MAX_STUDENTS) {
printf("文件中的学生数量超过系统上限,只加载前 %d 条,\n", MAX_STUDENTS);
student_count = MAX_STUDENTS;
}
// 读取所有学生数据
fread(students, sizeof(Student), student_count, fp);
fclose(fp);
printf("成功从文件 %s 加载了 %d 条学生信息!\n", filename, student_count);
}
main.c - 主程序入口
这个文件负责程序的流程控制,通过循环和switch语句来响应用户的选择。
#include "student.h"
int main() {
int choice;
// 程序启动时尝试从默认文件加载
// load_from_file(); // 如果希望启动时自动加载,可以取消这行注释
while (1) {
display_menu();
scanf("%d", &choice);
switch (choice) {
case 1:
add_student();
break;
case 2:
display_all_students();
break;
case 3:
find_student_by_id();
break;
case 4:
delete_student_by_id();
break;
case 5:
sort_students_by_score();
break;
case 6:
save_to_file();
break;
case 7:
load_from_file();
break;
case 0:
printf("感谢使用,再见!\n");
exit(0); // 退出程序
default:
printf("无效的输入,请重新选择!\n");
}
}
return 0;
}
如何编译和运行
-
保存文件: 将上面的三段代码分别保存为
student.h、student.c和main.c,并将它们放在同一个文件夹下。
(图片来源网络,侵删) -
编译: 打开终端(或命令提示符),进入该文件夹,使用GCC编译器进行编译,你需要将
.c文件编译并链接成一个可执行文件。# -o student_system 指定输出的可执行文件名为 student_system # main.c 是主程序 # student.c 是功能实现 # student.h 会被 main.c 和 student.c 自动包含 gcc main.c student.c -o student_system
-
运行: 编译成功后,在终端中运行生成的可执行文件。
- 在 Windows 上:
student_system.exe
- 在 Linux 或 macOS 上:
./student_system
- 在 Windows 上:
程序演示流程
- 程序启动,显示菜单。
- 选择
1,添加几个学生(101, "张三", 85.5; 102, "李四", 92.0; 103, "王五", 78.5)。 - 选择
2,查看所有学生信息,确认添加成功。 - 选择
5,按成绩排序。 - 再次选择
2,可以看到学生列表已按成绩从高到低排列。 - 选择
3,输入学号102,查找李四的信息。 - 选择
6,将信息保存到文件(students.dat)。 - 选择
0,退出程序。 - 重新运行程序,选择
7,从刚才保存的students.dat文件加载数据。 - 选择
2,可以看到之前保存的学生信息又回来了。
可以进一步改进的地方
这个程序已经具备了基本功能,但作为课程设计,你还可以考虑以下扩展:
- 数据持久化: 目前数据是保存在内存中的,退出程序就丢失了,虽然我们实现了文件读写,但可以让程序在启动时自动加载一个默认文件(如
students.dat),在退出时自动保存,提升用户体验。 - 输入验证: 对用户输入进行更严格的校验,
- 成绩必须在0-100之间。
- 学号必须是正整数。
- 姓名不能为空。
- 更丰富的排序: 增加按学号排序、按姓名排序等功能。
- 修改学生信息: 增加一个功能,允许用户根据学号修改某个学生的信息。
- 动态内存分配: 使用
malloc和realloc来动态分配内存,而不是使用固定大小的数组,这样可以处理任意数量的学生(仅受系统内存限制)。 - 更友好的用户界面: 使用更清晰的格式或简单的清屏函数(如
system("cls")或system("clear"))来美化界面。
希望这个详细的实现能帮助你完成你的C语言课程设计!

(图片来源网络,侵删)
