C 语言综合练习三:学生成绩管理系统
更新时间:2026-08-26。本文是
languages/c/主题入门层第 74 篇。前两个练习还是"小打小闹",这个直接上"管理系统":增删改查 + 文件持久化,是结构体、数组、文件 IO 的大阅兵。核心数据组织:结构体数组——现实中"一表多记录"的通用形态。代码已入库demos/c-beginner-practice/student_mgmt.c。
本文要回答的问题
- "管理系统"类程序的结构长什么样?
- 结构体数组怎么组织学生数据?
- 怎么把数据存进文件、下次再读回来?
一、需求拆解
功能菜单:
1. 添加学生
2. 显示全部
3. 按学号查找
4. 删除学生
5. 保存到文件
6. 从文件加载
0. 退出| 数据 | 结构 |
|---|---|
| 单个学生 | struct Student { int id; char name[32]; float score; } |
| 学生集合 | Student students[100] + int count |
| 持久化 | fprintf/fscanf 文本格式 |
二、完整代码
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
#define DB_FILE "students.txt"
typedef struct {
int id;
char name[32];
float score;
} Student;
Student students[MAX];
int count = 0;
void add_student(void) {
if (count >= MAX) { printf("容量已满\n"); return; }
Student *s = &students[count];
printf("学号 姓名 成绩:");
if (scanf("%d %s %f", &s->id, s->name, &s->score) == 3) {
count++;
printf("已添加\n");
} else {
printf("输入格式错误\n");
while (getchar() != '\n') { }
}
}
void list_students(void) {
if (count == 0) { printf("暂无学生\n"); return; }
for (int i = 0; i < count; i++)
printf("%d %s %.1f\n",
students[i].id, students[i].name, students[i].score);
}
int find_index(int id) {
for (int i = 0; i < count; i++)
if (students[i].id == id) return i;
return -1;
}
void delete_student(void) {
int id;
printf("输入要删除的学号:");
scanf("%d", &id);
int idx = find_index(id);
if (idx < 0) { printf("未找到\n"); return; }
/* 把最后一个元素挪过来覆盖,数组缩一位 */
students[idx] = students[count - 1];
count--;
printf("已删除\n");
}
void save_to_file(void) {
FILE *fp = fopen(DB_FILE, "w");
if (fp == NULL) { perror("保存失败"); return; }
fprintf(fp, "%d\n", count);
for (int i = 0; i < count; i++)
fprintf(fp, "%d %s %.1f\n",
students[i].id, students[i].name, students[i].score);
fclose(fp);
printf("已保存到 %s\n", DB_FILE);
}
void load_from_file(void) {
FILE *fp = fopen(DB_FILE, "r");
if (fp == NULL) { perror("加载失败"); return; }
fscanf(fp, "%d", &count);
for (int i = 0; i < count; i++)
fscanf(fp, "%d %s %f",
&students[i].id, students[i].name, &students[i].score);
fclose(fp);
printf("已加载 %d 条\n", count);
}
int main(void) {
int choice;
while (1) {
printf("\n--- 学生成绩管理系统 ---\n");
printf("1.添加 2.显示 3.查找 4.删除 5.保存 6.加载 0.退出\n");
printf("请选择:");
if (scanf("%d", &choice) != 1) { while (getchar() != '\n') { } continue; }
switch (choice) {
case 1: add_student(); break;
case 2: list_students(); break;
case 3: { int id; printf("学号:"); scanf("%d", &id);
int i = find_index(id);
if (i >= 0) printf("%d %s %.1f\n", students[i].id,
students[i].name, students[i].score);
else printf("未找到\n"); break; }
case 4: delete_student(); break;
case 5: save_to_file(); break;
case 6: load_from_file(); break;
case 0: printf("再见\n"); return 0;
default: printf("无效选项\n");
}
}
}三、关键设计点
1. 结构体数组是核心:
c
Student students[MAX]; // 一块连续内存装所有记录
int count; // 有效记录数数组 + 计数的模式贯穿所有"表"类程序。
2. 删除用"覆盖法":把最后一个元素挪到被删位置,count--——O(1) 且不移动中间元素,代价是顺序会变(对按 id 无序操作没问题)。
3. 文本持久化:首行存 count,随后每行一条记录——fprintf/fscanf 成对设计(格式化读写 讲过)。
四、运行演示
--- 学生成绩管理系统 ---
1.添加 2.显示 3.查找 4.删除 5.保存 6.加载 0.退出
请选择:1
学号 姓名 成绩:1001 alice 92.5
已添加
请选择:1
学号 姓名 成绩:1002 bob 88.0
已添加
请选择:2
1001 alice 92.5
1002 bob 88.0
请选择:5
已保存到 students.txt退出后重跑、选 6,数据原样回来。
五、扩展练习
六、一句话总结
c
/*
* student_mgmt.c —— C 语言入门综合练习三:学生成绩管理系统
* 文档: languages/c/beginner/74-practice-student-mgmt.md
* 编译: make && ./student_mgmt
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
#define DB_FILE "students.txt"
typedef struct {
int id;
char name[32];
float score;
} Student;
Student students[MAX];
int count = 0;
void add_student(void) {
if (count >= MAX) { printf("容量已满\n"); return; }
Student *s = &students[count];
printf("学号 姓名 成绩:");
if (scanf("%d %s %f", &s->id, s->name, &s->score) == 3) {
count++;
printf("已添加\n");
} else {
printf("输入格式错误\n");
while (getchar() != '\n') { }
}
}
void list_students(void) {
if (count == 0) { printf("暂无学生\n"); return; }
for (int i = 0; i < count; i++)
printf("%d %s %.1f\n",
students[i].id, students[i].name, students[i].score);
}
int find_index(int id) {
for (int i = 0; i < count; i++)
if (students[i].id == id) return i;
return -1;
}
void delete_student(void) {
int id;
printf("输入要删除的学号:");
scanf("%d", &id);
int idx = find_index(id);
if (idx < 0) { printf("未找到\n"); return; }
/* 把最后一个元素挪过来覆盖,数组缩一位 */
students[idx] = students[count - 1];
count--;
printf("已删除\n");
}
void save_to_file(void) {
FILE *fp = fopen(DB_FILE, "w");
if (fp == NULL) { perror("保存失败"); return; }
fprintf(fp, "%d\n", count);
for (int i = 0; i < count; i++)
fprintf(fp, "%d %s %.1f\n",
students[i].id, students[i].name, students[i].score);
fclose(fp);
printf("已保存到 %s\n", DB_FILE);
}
void load_from_file(void) {
FILE *fp = fopen(DB_FILE, "r");
if (fp == NULL) { perror("加载失败"); return; }
fscanf(fp, "%d", &count);
for (int i = 0; i < count; i++)
fscanf(fp, "%d %s %f",
&students[i].id, students[i].name, &students[i].score);
fclose(fp);
printf("已加载 %d 条\n", count);
}
int main(void) {
int choice;
while (1) {
printf("\n--- 学生成绩管理系统 ---\n");
printf("1.添加 2.显示 3.查找 4.删除 5.保存 6.加载 0.退出\n");
printf("请选择:");
if (scanf("%d", &choice) != 1) { while (getchar() != '\n') { } continue; }
switch (choice) {
case 1: add_student(); break;
case 2: list_students(); break;
case 3: { int id; printf("学号:"); scanf("%d", &id);
int i = find_index(id);
if (i >= 0) printf("%d %s %.1f\n", students[i].id,
students[i].name, students[i].score);
else printf("未找到\n"); break; }
case 4: delete_student(); break;
case 5: save_to_file(); break;
case 6: load_from_file(); break;
case 0: printf("再见\n"); return 0;
default: printf("无效选项\n");
}
}
}与本站主线衔接
- 结构体与数组,见结构体基础、结构体数组;
- 文件读写,见fopen 与 fclose、格式化读写;
- 排序与 qsort,见排序算法实现。