很多C语言初学者在论坛里发帖“跪求学生成绩管理系统的C语言源代码”,其实这个题目是课程设计里的常客,只要掌握结构体、数组、排序和文件读写,完全能自己写出来。下面给出一套经过本地编译的简化实现,环境为GCC 9.4,支持录入、排序、查询、保存和读取功能。
先定义学生结构体,包含学号、姓名、三门课程成绩以及总分和平均分。
```c
typedef struct {
char id[12];
char name[20];
float score[3];
float total;
float avg;
} Student;
```
设置全局数组和当前记录数,数组容量定为100个学生。
```c
Student stu[100];
int count = 0;
```

录入函数负责从键盘读入学生信息,每录完一个学生自动计算总分和平均分。学号长度为11位以内,姓名不超过19个字符。
```c
void input() {
if (count >= 100) {
printf("存储空间已满\n");
return;
}
printf("请输入学号: ");
scanf("%s", stu[count].id);
printf("请输入姓名: ");
scanf("%s", stu[count].name);
printf("请输入三门成绩: ");
scanf("%f%f%f", &stu[count].score[0], &stu[count].score[1], &stu[count].score[2]);
stu[count].total = stu[count].score[0] + stu[count].score[1] + stu[count].score[2];
stu[count].avg = stu[count].total / 3.0;
count++;
}
```
排序采用冒泡法,按总分降序排列,方便查看班级排名。
```c
void sort() {
for (int i = 0; i < count - 1; i++) {
for (int j = 0; j < count - 1 - i; j++) {
if (stu[j].total < stu[j + 1].total) {
Student temp = stu[j];
stu[j] = stu[j + 1];
stu[j + 1] = temp;
}
}
}
}
```
按学号查找时,线性遍历整个数组,找到返回索引,找不到返回-1。
```c
int searchByID(char *id) {
for (int i = 0; i < count; i++) {
if (strcmp(stu[i].id, id) == 0) {
return i;
}
}
return -1;
}
```
显示函数可以打印全部学生信息,也可以只打印某个学生。下面这个函数输出所有记录,并打印表头。
```c
void display() {
printf("%-12s %-10s %6s %6s %6s %8s %6s\n", "学号", "姓名", "成绩1", "成绩2", "成绩3", "总分", "均分");
for (int i = 0; i < count; i++) {
printf("%-12s %-10s %6.1f %6.1f %6.1f %8.1f %6.1f\n",
stu[i].id, stu[i].name,
stu[i].score[0], stu[i].score[1], stu[i].score[2],
stu[i].total, stu[i].avg);
}
}
```
文件保存功能把当前记录总数和所有学生结构体一次性写入二进制文件,文件名固定为students.dat。
```c
void save() {
FILE *fp = fopen("students.dat", "wb");
if (fp == NULL) {
printf("无法打开文件\n");
return;
}
fwrite(&count, sizeof(int), 1, fp);
fwrite(stu, sizeof(Student), count, fp);
fclose(fp);
}
```
读取文件时先读计数,再读数据,注意要判断文件是否存在。
```c
void load() {
FILE *fp = fopen("students.dat", "rb");
if (fp == NULL) {
printf("文件不存在\n");
return;
}
fread(&count, sizeof(int), 1, fp);
fread(stu, sizeof(Student), count, fp);
fclose(fp);
}
```
主函数用循环显示菜单,根据用户输入的数字调用对应功能。退出前提醒保存,避免数据丢失。
```c
int main() {
int choice;
char id[12];
while (1) {
printf("\n学生成绩管理系统\n");
printf("1.录入\n2.排序\n3.显示\n4.查找\n5.保存\n6.读取\n0.退出\n");
printf("请选择: ");
scanf("%d", &choice);
switch (choice) {
case 1:
input();
break;
case 2:
sort();
break;
case 3:
display();
break;
case 4:
printf("请输入要查找的学号: ");
scanf("%s", id);
int index = searchByID(id);
if (index == -1)
printf("未找到\n");
else {
printf("找到学生: %s, 总分 %.1f\n", stu[index].name, stu[index].total);
}
break;
case 5:
save();
printf("已保存\n");
break;
case 6:
load();
printf("已读取\n");
break;
case 0:
printf("程序结束\n");
return 0;
default:
printf("选项错误\n");
}
}
}
```
这个程序没有实现修改和删除功能,实际课程设计往往要求加上。修改可以先查找,然后重新输入该学生的成绩并更新总分。删除则把后面的元素整体前移一位,再把count减一。文件操作也可以改用文本格式,方便用Excel查看,但二进制格式更省空间。
刚接触C语言的人经常忘记在fopen之后判断返回值,这会导致程序在文件无法创建或打开时直接崩溃。另一个常见问题是在输入姓名时使用空格,导致scanf只读到空格前的部分,因此本程序用%s限制输入,不支持带空格的姓名。
整个系统大约150行代码,拷入编译器即可运行。与其在网络上“跪求”来路不明的源码,不如照着这个框架自己敲一遍,遇到错误就调试,几个月后你会感谢曾经认真的自己。