最近在问答上帮提问者回答问题,有遇到求C语言实现学生管理成绩系统,需求非常简单,就顺手码了下代码。我觉得这种比较小的系统,可以收录起来,做一个C语言基础学习目录也是不错的主意。
因为当时的问题已经找不到了,我就回想着把问题的大致说一下。
一 题目
简单实现一个学生成绩系统,一个学生包含学号,姓名,年龄,数学成绩,计算机成绩,总成绩六项信息,学号唯一,姓名可以重名。
数据格式如下:
学号 | 姓名 | 年龄 | 数学 | 计算机 | 总分 |
---|---|---|---|---|---|
int | char[20] | int | int | int | int |
需实现以下功能:
(1) 添加学生信息
(2) 浏览学生信息
(3) 查询学生信息
(4) 删除学生信息
(5) 按总分排序
(6) 退出系统
使用过程需要有简单的描述性语句,便于操作者使用。
总体来说,回忆题目大致是如此,不影响对后续代码的实现和阅读。
二 设计
1.单个学生信息
这个就按照数据格式表格要求来即可,使用C语言结构体定义学生信息,C语言中的结构体可以存储复杂的数据。
typedef struct Student{
int id; //学号
char name[20]; //名字
int age; //年龄
int math; //数学成绩
int computer; //计算机成绩
int total; //总分
}Stu;
2.存放学生信息
因为不知道有多少学生信息,而且学生信息支持增删改查,这里采用单链表的形式来存放学生数据,以下是链表的数据结构
typedef struct StudentData{
Stu student;
struct StudentData * next;
}StuData, *PStuData;
3.定义布尔型数据
将是和否值1,0定义为宏,对一些常用的数值定义为宏,不失为一个好的编码习惯。这个是给后面判断语句和循环语句使用。
//定义布尔
#define TRUE 1
#define FALSE 0
typedef short BOOL;
4.函数设计
//选择主菜单
int EnterMainMenu();
//申请数据内存
PStuData GetPStuData();
//释放数据内存
void FreePStuData(PStuData pData);
//添加学生
void AddStudent(PStuData pHead);
//删除学生
void RemoveStudent(PStuData pHead);
//浏览学生信息
void DisplayStudents(PStuData pHead);
//查询学生信息
void QueryStudent(PStuData pHead);
//排序并显示
void SortStudents(PStuData pHead);
//Student数据复制
void CopyStudent(Stu * st1, Stu * st2);
//返回主菜单
void BackMain();
//清屏操作
void ClearScreen();
//清空输入缓冲
void ClearStdin();
后面会着重说明和实现这些函数的作用和功能。
三 代码实现
1.主菜单选择
使用puts输出字符串打印菜单信息,通过scanf接收屏幕上输入的选择信息。getchar函数是接收一个字符,在scanf使用中换行代表输入结束,但是这个换行会停留在输入缓存区里面,这里接收掉是为了不干扰后续的输入和显示。
int EnterMainMenu(){
int menu;
//打印菜单
puts("请选择系统功能(按对应数字,回车执行)");
puts("(1) 添加学生信息");
puts("(2) 浏览学生信息");
puts("(3) 查询学生信息");
puts("(4) 删除学生信息");
puts("(5) 按总分排序");
puts("(6) 退出系统");
scanf("%d", &menu);
//接收多余的回车键
getchar();
return menu;
}
2.返回主菜单
封装函数功能,getchar()函数获取一个任意字符,返回主菜单。
void BackMain(){
ClearStdin();//清理输入缓存区,后续展示该函数功能
printf("输入任何字符返回主菜单");
getchar();
ClearScreen();//清理屏幕信息,后续展示该函数功能
}
3.主函数main实现
使用switch(开关语句)对菜单输入进行控制流程。
int main(){
int menu;
BOOL doing = TRUE;
PStuData pData = NULL;
pData = GetPStuData();//申请数据内存,后续会解释此函数
if(pData == NULL){
doing = FALSE;
}
while(doing){
menu = EnterMainMenu();
switch(menu){
case 1:
AddStudent(pData);
break;
case 2:
DisplayStudents(pData);
break;
case 3:
QueryStudent(pData);
break;
case 4:
RemoveStudent(pData);
break;
case 5:
SortStudents(pData);
break;
case 6:
doing = FALSE;
puts("退出系统");
break;
default:
puts("输入错误!");
break;
}
}
return 0;
}
4.内存申请和释放
因为不知道具体学生信息的数量,而且还需要支持增、删功能。那么我们就需要动态的分配内存来存储学生信息数据, 使用stdlib.h库中的malloc函数动态申请内存和free函数释放内存。
PStuData GetPStuData(){
PStuData pData = NULL;
pData = (PStuData)malloc(sizeof(StuData));
if(pData){
pData->next = NULL;
}
return pData;
}
void FreePStuData(PStuData pData){
if(pData != NULL){
free(pData);
}
}
5.添加学生信息
获取屏幕录入的学生信息,按学号升序添加到学生信息单链表中。
void AddStudent(PStuData pHead){
BOOL bUpdate = FALSE;
int id, age, math, computer;
char name[20];
char loop[20];
PStuData pVisit = NULL;
PStuData pLast = NULL;
PStuData pNew = NULL;
ClearScreen();//清屏,后续展示该函数功能
puts("===录入学生信息===");
printf("请输入学生学号:");
scanf("%d", &id);
printf("请输入学生姓名:");
scanf("%s", name);
printf("请输入学生年龄:");
scanf("%d", &age);
printf("请输入学生数学成绩:");
scanf("%d", &math);
printf("请输入学生计算机成绩:");
scanf("%d", &computer);
pNew = GetPStuData();
if(!pNew){
puts("内存空间不足,无法添加学生信息");
BackMain();
return;
}
pNew->student.id = id;
strcpy(pNew->student.name, name);
pNew->student.age = age;
pNew->student.math = math;
pNew->student.computer = computer;
pNew->student.total = math + computer;
pVisit = pHead->next;
pLast = NULL;
while(pVisit){
//仅更新数据
if(pVisit->student.id == id){
CopyStudent(&pVisit->student, &pNew->student);//封装,相当于student的数据赋值
//清理申请的内存
FreePStuData(pNew);
bUpdate = TRUE;
break;
}
if(pVisit->student.id > id){
break;
}
pLast = pVisit;
pVisit = pLast->next;
}
//找到插入节点
if(pLast){
pNew->next = pLast->next;
pLast->next = pNew;
}
else if(!bUpdate){//添加的首个元素
pHead->next = pNew;
}
if(bUpdate){
puts("更新学生信息完成");
}
else{
puts("添加学生信息完成");
}
//清理
pNew = NULL;
pVisit = NULL;
bUpdate = FALSE;
BackMain();
}
6.学生信息拷贝赋值
封装函数功能,拷贝赋值学生信息,其中学生名字不能直接赋值,需要string.h库中的strcpy函数进行操作。
void CopyStudent(Stu * st1, Stu * st2){
st1->id = st2->id;
strcpy(st1->name, st2->name);//字符串不能直接赋值,需要string.h库中的strcpy函数进行操作
st1->age = st2->age;
st1->math = st2->math;
st1->computer = st2->computer;
st1->total = st2->total;
}
7.查询学生信息
获取录入的学号,顺序迭代访问单链表,查询显示该学号的学生信息。
void QueryStudent(PStuData pHead){
PStuData pVisit = NULL;
int id;
ClearScreen();//清屏,后续展示该函数功能
printf("请输入要查询学生信息的学号:");
scanf("%d", &id);
pVisit = pHead->next;
while(pVisit){
if(pVisit->student.id == id){
printf("查询信息 学号:%d 姓名:%s 年龄:%d 数学:%d 计算机:%d 总分:%d\n",
pVisit->student.id, pVisit->student.name, pVisit->student.age, pVisit->student.math,
pVisit->student.computer, pVisit->student.total);
break;
}
pVisit = pVisit->next;
}
if(!pVisit){
printf("查询id无效");
}
BackMain();
}
8.展示学生信息
顺序迭代访问单链表,显示所有学生信息。
void DisplayStudents(PStuData pHead){
PStuData pData = NULL;
ClearScreen();//清屏,后续展示该函数
if(pHead){
pData = pHead->next;
}
if(!pData){
puts("没有学生数据信息");
}
else{
printf("%-10s| %-20s| %-5s| %-5s| %-6s| %-5s|\n", "学号", "姓名", "年龄", "数学", "计算机", "总分");
}
while(pData){
printf("%-10d| %-20s| %-5d| %-5d| %-6d| %-5d|\n", pData->student.id, pData->student.name,
pData->student.age, pData->student.math, pData->student.computer, pData->student.total);
pData = pData->next;
}
BackMain();
}
9.删除学生信息
获取输入学号,删除单链表中匹配的学生信息。
void RemoveStudent(PStuData pHead){
PStuData pVisit = NULL;
PStuData pLast = NULL;
int id;
ClearScreen();//清屏
printf("请输入要删除学生信息的学号:");
scanf("%d", &id);
pVisit = pHead->next;
pLast = pHead;
while(pVisit){
if(pVisit->student.id == id){
break;
}
pLast = pVisit;
pVisit = pLast->next;
}
if(pVisit){
pLast->next = pVisit->next;
FreePStuData(pVisit);
printf("删除学号为%d的信息成功\n", id);
}
else{
printf("删除学号为%d的信息失败,学生不存在\n", id);
}
BackMain();
}
10.升序排序学生总成绩并显示出来
这里的做法是创建新的单链表,使用插入法排序。
void SortStudents(PStuData pHead){
PStuData pVisit = NULL;
PStuData pSortHead = NULL;
PStuData pSortVisit = NULL;
PStuData pSortLast = NULL;
PStuData pNew = NULL;
pVisit = pHead->next;
pSortHead = GetPStuData();
while(pVisit){
pSortVisit = pSortHead->next;
pSortLast = pSortHead;
while(pSortVisit){
if(pSortVisit->student.total >= pVisit->student.total){
break;
}
pSortLast = pSortVisit;
pSortVisit = pSortVisit->next;
}
pNew = GetPStuData();
CopyStudent(&pNew->student, &pVisit->student);
pNew->next = pSortVisit;
pSortLast->next = pNew;
pVisit = pVisit->next;
}
DisplayStudents(pSortHead);
pSortVisit = NULL;
while(pSortHead){
pSortVisit = pSortHead->next;
FreePStuData(pSortHead);
pSortHead = pSortVisit;
}
}
11.其他函数
void ClearScreen(){
system("cls");
}
void ClearStdin(){
setbuf(stdin, NULL);
}
四 整体代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//定义布尔
#define TRUE 1
#define FALSE 0
typedef short BOOL;
//学生数据
typedef struct Student{
int id; //学号
char name[20]; //名字
int age; //年龄
int math; //数学成绩
int computer; //计算机成绩
int total; //总分
}Stu;
typedef struct StudentData{
Stu student;
struct StudentData * next;
}StuData, *PStuData;
//选择主菜单
int EnterMainMenu();
//申请数据内存
PStuData GetPStuData();
//释放数据内存
void FreePStuData(PStuData pData);
//添加学生
void AddStudent(PStuData pHead);
//删除学生
void RemoveStudent(PStuData pHead);
//浏览学生信息
void DisplayStudents(PStuData pHead);
//查询学生信息
void QueryStudent(PStuData pHead);
//排序并显示
void SortStudents(PStuData pHead);
//Student数据复制
void CopyStudent(Stu * st1, Stu * st2);
//返回主菜单
void BackMain();
//清屏操作
void ClearScreen();
//清空输入缓冲
void ClearStdin();
int main(){
int menu;
BOOL doing = TRUE;
PStuData pData = NULL;
pData = GetPStuData();
if(pData == NULL){
doing = FALSE;
}
while(doing){
menu = EnterMainMenu();
switch(menu){
case 1:
AddStudent(pData);
break;
case 2:
DisplayStudents(pData);
break;
case 3:
QueryStudent(pData);
break;
case 4:
RemoveStudent(pData);
break;
case 5:
SortStudents(pData);
break;
case 6:
doing = FALSE;
puts("退出系统");
break;
default:
puts("输入错误!");
break;
}
}
return 0;
}
PStuData GetPStuData(){
PStuData pData = NULL;
pData = (PStuData)malloc(sizeof(StuData));
if(pData){
pData->next = NULL;
}
return pData;
}
void FreePStuData(PStuData pData){
if(pData != NULL){
free(pData);
}
}
int EnterMainMenu(){
int menu;
//打印菜单
puts("请选择系统功能(按对应数字,回车执行)");
puts("(1) 添加学生信息");
puts("(2) 浏览学生信息");
puts("(3) 查询学生信息");
puts("(4) 删除学生信息");
puts("(5) 按总分排序");
puts("(6) 退出系统");
scanf("%d", &menu);
//接收多余的回车键
getchar();
return menu;
}
void AddStudent(PStuData pHead){
BOOL bUpdate = FALSE;
int id, age, math, computer;
char name[20];
char loop[20];
PStuData pVisit = NULL;
PStuData pLast = NULL;
PStuData pNew = NULL;
ClearScreen();
puts("===录入学生信息===");
printf("请输入学生学号:");
scanf("%d", &id);
printf("请输入学生姓名:");
scanf("%s", name);
printf("请输入学生年龄:");
scanf("%d", &age);
printf("请输入学生数学成绩:");
scanf("%d", &math);
printf("请输入学生计算机成绩:");
scanf("%d", &computer);
pNew = GetPStuData();
if(!pNew){
puts("内存空间不足,无法添加学生信息");
BackMain();
return;
}
pNew->student.id = id;
strcpy(pNew->student.name, name);
pNew->student.age = age;
pNew->student.math = math;
pNew->student.computer = computer;
pNew->student.total = math + computer;
pVisit = pHead->next;
pLast = NULL;
while(pVisit){
//仅更新数据
if(pVisit->student.id == id){
CopyStudent(&pVisit->student, &pNew->student);
//清理申请的内存
FreePStuData(pNew);
bUpdate = TRUE;
break;
}
if(pVisit->student.id > id){
break;
}
pLast = pVisit;
pVisit = pLast->next;
}
//找到插入节点
if(pLast){
pNew->next = pLast->next;
pLast->next = pNew;
}
else if(!bUpdate){//添加的首个元素
pHead->next = pNew;
}
if(bUpdate){
puts("更新学生信息完成");
}
else{
puts("添加学生信息完成");
}
//清理
pNew = NULL;
pVisit = NULL;
bUpdate = FALSE;
BackMain();
}
void DisplayStudents(PStuData pHead){
PStuData pData = NULL;
ClearScreen();
if(pHead){
pData = pHead->next;
}
if(!pData){
puts("没有学生数据信息");
}
else{
printf("%-10s| %-20s| %-5s| %-5s| %-6s| %-5s|\n", "学号", "姓名", "年龄", "数学", "计算机", "总分");
}
while(pData){
printf("%-10d| %-20s| %-5d| %-5d| %-6d| %-5d|\n", pData->student.id, pData->student.name,
pData->student.age, pData->student.math, pData->student.computer, pData->student.total);
pData = pData->next;
}
BackMain();
}
void QueryStudent(PStuData pHead){
PStuData pVisit = NULL;
int id;
ClearScreen();
printf("请输入要查询学生信息的学号:");
scanf("%d", &id);
pVisit = pHead->next;
while(pVisit){
if(pVisit->student.id == id){
printf("查询信息 学号:%d 姓名:%s 年龄:%d 数学:%d 计算机:%d 总分:%d\n",
pVisit->student.id, pVisit->student.name, pVisit->student.age, pVisit->student.math,
pVisit->student.computer, pVisit->student.total);
break;
}
pVisit = pVisit->next;
}
if(!pVisit){
printf("查询id无效");
}
BackMain();
}
void RemoveStudent(PStuData pHead){
PStuData pVisit = NULL;
PStuData pLast = NULL;
int id;
ClearScreen();
printf("请输入要删除学生信息的学号:");
scanf("%d", &id);
pVisit = pHead->next;
pLast = pHead;
while(pVisit){
if(pVisit->student.id == id){
break;
}
pLast = pVisit;
pVisit = pLast->next;
}
if(pVisit){
pLast->next = pVisit->next;
FreePStuData(pVisit);
printf("删除学号为%d的信息成功\n", id);
}
else{
printf("删除学号为%d的信息失败,学生不存在\n", id);
}
BackMain();
}
void SortStudents(PStuData pHead){
PStuData pVisit = NULL;
PStuData pSortHead = NULL;
PStuData pSortVisit = NULL;
PStuData pSortLast = NULL;
PStuData pNew = NULL;
pVisit = pHead->next;
pSortHead = GetPStuData();
while(pVisit){
pSortVisit = pSortHead->next;
pSortLast = pSortHead;
while(pSortVisit){
if(pSortVisit->student.total >= pVisit->student.total){
break;
}
pSortLast = pSortVisit;
pSortVisit = pSortVisit->next;
}
pNew = GetPStuData();
CopyStudent(&pNew->student, &pVisit->student);
pNew->next = pSortVisit;
pSortLast->next = pNew;
pVisit = pVisit->next;
}
DisplayStudents(pSortHead);
pSortVisit = NULL;
while(pSortHead){
pSortVisit = pSortHead->next;
FreePStuData(pSortHead);
pSortHead = pSortVisit;
}
}
void CopyStudent(Stu * st1, Stu * st2){
st1->id = st2->id;
strcpy(st1->name, st2->name);
st1->age = st2->age;
st1->math = st2->math;
st1->computer = st2->computer;
st1->total = st2->total;
}
void BackMain(){
ClearStdin();
printf("输入任何字符返回主菜单");
getchar();
ClearScreen();
}
void ClearScreen(){
system("cls");
}
void ClearStdin(){
setbuf(stdin, NULL);
}
演示:
至此,该学生成绩管理系统介绍完毕,其中都是采用比较简单的做法。当然这里可以进一步优化,比如数据可以存储到文件而不用每次都重新输入等等,但不影响此系统的小全的功能,我就不上文件存储功能的代码了。
网友评论