C语言-学生成绩管理系统
前言
最近在复习C语言和数据结构,于是用纯C语言单链表写个成绩管理系统练练手。
实现的功能
系统的主界面如下:
如界面所示,主要实现了以下功能:
- 增加记录
- 删除记录
- 查询记录
- 修改记录
- 排序
- 求和求平均分
写的比较简单,但是这些基本的功能都实现了,希望能给大家起一个抛砖引玉的作用。
该系统有很多可以优化的空间,比如可以使用清屏函数system(“cls”); (其头文件为stdlib.h)来获得更好的体验。
添加学生信息
实现了头插法、尾插法和整体遍历。
//添加学生
bool add_student(stu *L)
{
int number;//学号
char name[10];//姓名
int Chinese;//语文成绩
int maths;//数学成绩
int English;//英语成绩
printf("请依次输入以下信息:学号、姓名、语文成绩、数学成绩、英语成绩(每输完一个项回车输入下一个)\n");
scanf("%d",&number);
scanf("%s",name);
scanf("%d",&Chinese);
scanf("%d",&maths);
scanf("%d",&English);
//新申请一个内存空间
stu *p; //指针P指向当前扫描到的结点
p = L; //L指向头结点,头结点是第0个结点(不存数据)
stu *s = (stu *)malloc(sizeof(stu));
//为新结点赋值
s->number = number;
for(int i=0;i<sizeof(name);i++) //数组元素赋值不能让数组直接等于数组
s->name[i] = name[i];
s->Chinese = Chinese;
s->maths = maths;
s->English = English;
//指针的改变
s->next = p->next;
p->next = s;
return true;
}
//显示所有信息,整体遍历
void show_all(stu *L)
{
printf("所有学生信息如下:\n");
printf("学号\t姓名\t语文成绩\t数学成绩\t英语成绩\t\n");
stu *p;
p = L->next;//p指向头结点
while(p!=NULL)
{
printf("%4d %s %3d %3d %3d\n",p->number,p->name,p->Chinese,p->maths,p->English);
p = p->next;
}
}
以上是根据头插法实现的,尾插法思路:跟头插法类似,p首先等于头指针,先让其一直向后移动,直到指向末尾,才进行结点插入操作。
//添加学生
bool add_student(stu *L)
{
//头插法
int number;//学号
char name[10];//姓名
int Chinese;//语文成绩
int maths;//数学成绩
int English;//英语成绩
printf("请依次输入以下信息:学号、姓名、语文成绩、数学成绩、英语成绩(每输完一个项回车输入下一个)\n");
scanf("%d",&number);
scanf("%s",name);
scanf("%d",&Chinese);
scanf("%d",&maths);
scanf("%d",&English);
//新申请一个内存空间
stu *p; //指针P指向当前扫描到的结点
p = L; //L指向头结点,头结点是第0个结点(不存数据)
stu *s = (stu *)malloc(sizeof(stu));
//为新结点赋值
s->number = number;
for(int i=0;i<sizeof(name);i++) //数组元素赋值不能让数组直接等于数组
s->name[i] = name[i];
s->Chinese = Chinese;
s->maths = maths;
s->English = English;
//------------尾插法------------//
//尾插法主要多了这个while循环
while(p->next!=NULL)
{
p = p->next;
}
s->next = p->next;
p->next = s;
//------------尾插法------------//
return true;
}
根据学号查询
按学号查询的思路很简单,只要用指针遍历,然后比较指针指向的数据的学号跟自己查询的学号是否一致,若一致则输出,若不一致则继续循环。
//根据学号查询
bool search_num(stu *L,int num)
{
stu *p;
p = L->next;
while(p!=NULL)
{
if(p->number == num)
{
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",p->number,p->name,p->Chinese,p->maths,p->English);
return true;
}
p = p->next;
}
return false;
}
根据学号删除学生记录
删除跟查询有点小区别。删除首先需要找到你要删除的结点数据,但是由于这个是单链表,所以需要找到要删除的结点的前一个结点,把前一个结点的指针直接修改为指向你要删除的结点的下一个结点,然后将你要删除的结点释放即可。
//根据学号删除
bool del_student(stu *L,int num)
{
stu *p;
p = L;//让p从头开始
while(p->next!=NULL)
{
stu *q = p->next; // q指向被删除的结点
if(q->number == num) //p的下一个若是想要删除的结点数据
{
printf("您删除的结点数据为:\n%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",q->number,q->name,q->Chinese,q->maths,q->English);
p->next = q->next;//执行删除操作
free(q);
return true;
}
p = p->next;
}
return false;
}
根据学号查询并修改信息
修改也很简单。修改需要先查询,查询到数据之后,将数据作一个赋值操作即可。
//根据学号查询并修改信息
bool verify_num(stu *L,int num)
{
stu *p;
p = L->next;
while(p!=NULL)
{
if(p->number == num)
{
printf("您要修改的信息为:\n学号\t姓名\t语文成绩\t数学成绩\t英语成绩\t\n");
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",p->number,p->name,p->Chinese,p->maths,p->English);
int number;//学号
char name[10];//姓名
int Chinese;//语文成绩
int maths;//数学成绩
int English;//英语成绩
printf("请重新输入以下信息:学号、姓名、语文成绩、数学成绩、英语成绩(每输完一个项回车输入下一个)\n");
scanf("%d",&number);
scanf("%s",name);
scanf("%d",&Chinese);
scanf("%d",&maths);
scanf("%d",&English);
//为该结点赋值
p->number = number;
for(int i=0;i<sizeof(name);i++) //数组元素赋值不能让数组直接等于数组
p->name[i] = name[i];
p->Chinese = Chinese;
p->maths = maths;
p->English = English;
return true;
}
p = p->next;
}
return false;
}
根据语文成绩从高到低排序
排序这个稍微复杂一点点,因为步骤比较多。需要注意的是,排序不能改变原来链表的结构,所以我做了一个将链表数据取出放入一个数组的操作,然后再对这个数组进行排序操作。
//根据语文成绩排序
bool sort_Chinese(stu *L)
{
int numbers = 0;//先统计出有多少条记录
stu *p;
p = L->next;
while(p!=NULL)
{
numbers++;
p = p->next;
}
printf("一共找到%d条学生记录!\n",numbers);
stu data[numbers]; //把所有的数据存入这个数组里,对这个数组进行统计操作
p = L->next;//让p重新指向开头
for(int i=0;i<numbers;i++)
{
if(p!=NULL)
{
data[i].number = p->number;
for(int j=0;j<sizeof(p->name);j++) //数组元素赋值不能让数组直接等于数组
data[i].name[j] = p->name[j];
data[i].Chinese = p->Chinese;
data[i].maths = p->maths;
data[i].English = p->English;
p = p->next;
}
}
int temp_num;//临时学号
char temp_name[10];
int temp_Chinese;
int temp_maths;
int temp_English;
//根据语文成绩进行排序
for(int i=0;i<numbers-1;i++)
{
for(int j=0;j<numbers-1-i;j++)
{
if(data[j].Chinese<data[j+1].Chinese)
{
//交换学号
temp_num = data[j+1].number;
data[j+1].number = data[j].number;
data[j].number = temp_num;
//交换姓名
for(int k=0;k<sizeof(data[0].name);k++) //数组元素赋值不能让数组直接等于数组
{
temp_name[k] = data[j+1].name[k];
data[j+1].name[k] = data[j].name[k];
data[j].name[k] = temp_name[k];
}
//交换语文成绩
temp_Chinese = data[j+1].Chinese;
data[j+1].Chinese = data[j].Chinese;
data[j].Chinese = temp_Chinese;
//交换数学成绩
temp_maths = data[j+1].maths;
data[j+1].maths = data[j].maths;
data[j].maths = temp_maths;
//交换英语成绩
temp_English = data[j+1].English;
data[j+1].English = data[j].English;
data[j].English = temp_English;
}
}
}
//输出排序后的结果
printf("排序后的结果如下(语文成绩从高到低排序):\n学号\t姓名\t语文成绩\t数学成绩\t英语成绩\t\n");
for(int i=0;i<numbers;i++)
{
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",data[i].number,data[i].name,data[i].Chinese,data[i].maths,data[i].English);
}
}
全部代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h> //根据C99标准,C语言使用bool类型需要添加这个头文件
//结构体声明部分
typedef struct Student
{
int number;//学号
char name[10];//姓名
int Chinese;//语文成绩
int maths;//数学成绩
int English;//英语成绩
struct Student *next; //指向后一个元素的指针
}stu,*stuList;
/*--------函数声明部分--------*/
void MainMenu();//主菜单,用于显示
bool add_student(stu *L);//添加学生记录
void show_all(stu *L);//显示所有学生信息
bool del_student(stu *L,int num);//根据学号删除学生信息
bool search_num(stu *L,int num);//根据学号查询
bool verify_num(stu *L,int num);//根据学号查询信息并修改
bool sort_Chinese(stu *L);//根据语文成绩排序
bool InitList(stu *L);//学生链表初始化
bool Empty(stu *L);//链表判空操作
/*--------函数声明部分--------*/
int main()
{
int ch;//选择的序号
int ch_num;//根据学号进行查询、删除、修改等操作
stu L;
if(InitList(&L))
printf("链表初始化成功!\n");//提示信息,如果不需要可删除,但一定要先进行链表初始化!
else
printf("链表初始化失败!\n");
while(1)
{
MainMenu();//显示主界面
printf("\n请输入您要执行的操作序号:");
scanf("%d",&ch);
switch(ch)
{
case 0: printf("感谢您的使用!"); exit(0); break;
case 1: add_student(&L); break;
case 2: printf("请输入您要删除的学生的学号:");
scanf("%d",&ch_num);
if(del_student(&L,ch_num))
printf("删除成功!\n");
else
printf("删除失败,无此项记录!\n");
break;
case 3: printf("请输入您要修改的学生的学号:");
scanf("%d",&ch_num);
if(verify_num(&L,ch_num))
printf("修改成功!\n");
else
printf("修改失败,无此项记录!\n");
break;
case 4:
printf("请输入您要查询的学号:");
scanf("%d",&ch_num);
if(search_num(&L,ch_num))
printf("查询成功!\n");
else
printf("查询失败,无此项记录!\n");
break;
case 5:
sort_Chinese(&L); break;
case 6: show_all(&L); break;
default: printf("您输入的操作序号有误,请重新输入!\n");
}
}
return 0;
}
//主菜单,显示
void MainMenu()
{
printf("\n\n\n");
printf("\t **********学生成绩管理系统***********\n");
printf("\t ------- 0.退出系统 \n\n");
printf("\t ------- 1.录入学生成绩\n\n");
printf("\t ------- 2.删除记录\n\n");
printf("\t ------- 3.修改学生信息\n\n");
printf("\t ------- 4.查询学生信息\n\n");
printf("\t ------- 5.按语文成绩排序\n\n");
printf("\t ------- 6.显示所有学生信息\n\n");
printf("\t *************************************\n");
}
//初始化单链表(带头结点)
bool InitList(stu *L)
{
L = (stu *)malloc(sizeof(stu)); //分配一个头结点
if (L==NULL) //内存不足,分配失败
return false;
L->next = NULL; //头结点之后暂时还没有节点
return true;
}
//添加学生
bool add_student(stu *L)
{
int number;//学号
char name[10];//姓名
int Chinese;//语文成绩
int maths;//数学成绩
int English;//英语成绩
printf("请依次输入以下信息:学号、姓名、语文成绩、数学成绩、英语成绩(每输完一个项回车输入下一个)\n");
scanf("%d",&number);
scanf("%s",name);
scanf("%d",&Chinese);
scanf("%d",&maths);
scanf("%d",&English);
//新申请一个内存空间
stu *p; //指针P指向当前扫描到的结点
p = L; //L指向头结点,头结点是第0个结点(不存数据)
stu *s = (stu *)malloc(sizeof(stu));
//为新结点赋值
s->number = number;
for(int i=0;i<sizeof(name);i++) //数组元素赋值不能让数组直接等于数组
s->name[i] = name[i];
s->Chinese = Chinese;
s->maths = maths;
s->English = English;
//------------头插法------------//
//指针的改变
// s->next = p->next;
// p->next = s;
//------------头插法------------//
//------------尾插法------------//
//注:尾插法主要是多了这个while循环,即先让指针指向链表末尾再进行插入操作
while(p->next!=NULL)
{
p = p->next;
}
s->next = p->next;
p->next = s;
//------------尾插法------------//
return true;
}
//显示所有信息
void show_all(stu *L)
{
printf("所有学生信息如下:\n");
printf("学号\t姓名\t语文成绩\t数学成绩\t英语成绩\t\n");
stu *p;
p = L->next;
while(p!=NULL)
{
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",p->number,p->name,p->Chinese,p->maths,p->English);
p = p->next;
}
}
//根据学号查询
bool search_num(stu *L,int num)
{
stu *p;
p = L->next;
while(p!=NULL)
{
if(p->number == num)
{
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",p->number,p->name,p->Chinese,p->maths,p->English);
return true;
}
p = p->next;
}
return false;
}
//根据学号删除
bool del_student(stu *L,int num)
{
stu *p;
p = L;//让p从头开始
while(p->next!=NULL)
{
stu *q = p->next; // q指向被删除的结点
if(q->number == num) //p的下一个若是想要删除的结点数据
{
printf("您删除的结点数据为:\n%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",q->number,q->name,q->Chinese,q->maths,q->English);
p->next = q->next;//执行删除操作
free(q);
return true;
}
p = p->next;
}
return false;
}
//根据学号查询并修改信息
bool verify_num(stu *L,int num)
{
stu *p;
p = L->next;
while(p!=NULL)
{
if(p->number == num)
{
printf("您要修改的信息为:\n学号\t姓名\t语文成绩\t数学成绩\t英语成绩\t\n");
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",p->number,p->name,p->Chinese,p->maths,p->English);
int number;//学号
char name[10];//姓名
int Chinese;//语文成绩
int maths;//数学成绩
int English;//英语成绩
printf("请重新输入以下信息:学号、姓名、语文成绩、数学成绩、英语成绩(每输完一个项回车输入下一个)\n");
scanf("%d",&number);
scanf("%s",name);
scanf("%d",&Chinese);
scanf("%d",&maths);
scanf("%d",&English);
//为该结点赋值
p->number = number;
for(int i=0;i<sizeof(name);i++) //数组元素赋值不能让数组直接等于数组
p->name[i] = name[i];
p->Chinese = Chinese;
p->maths = maths;
p->English = English;
return true;
}
p = p->next;
}
return false;
}
//根据语文成绩排序
bool sort_Chinese(stu *L)
{
int numbers = 0;//先统计出有多少条记录
stu *p;
p = L->next;
while(p!=NULL)
{
numbers++;
p = p->next;
}
printf("一共找到%d条学生记录!\n",numbers);
stu data[numbers]; //把所有的数据存入这个数组里,对这个数组进行统计操作
p = L->next;//让p重新指向开头
for(int i=0;i<numbers;i++)
{
if(p!=NULL)
{
data[i].number = p->number;
for(int j=0;j<sizeof(p->name);j++) //数组元素赋值不能让数组直接等于数组
data[i].name[j] = p->name[j];
data[i].Chinese = p->Chinese;
data[i].maths = p->maths;
data[i].English = p->English;
p = p->next;
}
}
// printf("存进数组后:\n"); //可以查看存进的结果是否正确
// for(int i=0;i<numbers;i++)
// {
// printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",data[i].number,data[i].name,data[i].Chinese,data[i].maths,data[i].English);
// }
int temp_num;//临时学号
char temp_name[10];
int temp_Chinese;
int temp_maths;
int temp_English;
//根据语文成绩进行排序
for(int i=0;i<numbers-1;i++)
{
for(int j=0;j<numbers-1-i;j++)
{
if(data[j].Chinese<data[j+1].Chinese)
{
//交换学号
temp_num = data[j+1].number;
data[j+1].number = data[j].number;
data[j].number = temp_num;
//交换姓名
for(int k=0;k<sizeof(data[0].name);k++) //数组元素赋值不能让数组直接等于数组
{
temp_name[k] = data[j+1].name[k];
data[j+1].name[k] = data[j].name[k];
data[j].name[k] = temp_name[k];
}
//交换语文成绩
temp_Chinese = data[j+1].Chinese;
data[j+1].Chinese = data[j].Chinese;
data[j].Chinese = temp_Chinese;
//交换数学成绩
temp_maths = data[j+1].maths;
data[j+1].maths = data[j].maths;
data[j].maths = temp_maths;
//交换英语成绩
temp_English = data[j+1].English;
data[j+1].English = data[j].English;
data[j].English = temp_English;
}
}
}
//输出排序后的结果
printf("排序后的结果如下(语文成绩从高到低排序):\n学号\t姓名\t语文成绩\t数学成绩\t英语成绩\t\n");
for(int i=0;i<numbers;i++)
{
printf("%-4d\t%s\t%-3d\t\t%-3d\t\t%-3d\n",data[i].number,data[i].name,data[i].Chinese,data[i].maths,data[i].English);
}
}