学生成绩管理是学校教务部门日常工作的重要组成部分,其处理信息量很大。本项目是对学生成绩管理的简单模拟,用菜单选择方式完成下列功能:输入学生数据;输出学生数据;学生数据查询;添加学生数据;修改学生数据;删除学生数据。
本项目的实质是完成对学生成绩信息的建立、查找、插入、修改、删除等功能,可以首先定义项目的数据结构,然后将每功能写成一个函数来完成对数据的操作,最后完成主函数以验证各个函数功能并得出运行结果
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define NAME_MAX 50
#define ID_MAX 20
typedef struct student{
char name[NAME_MAX]; //学生姓名
char id[ID_MAX]; //学号
int grade; //成绩
struct student *next; //指向下一个学生信息
}stu;
//声明功能函数
///void n_built(stu *head); //添加学生信息
///void modify(stu *head); //修改学生信息
///void delOne(stu *head); //删除某一学生信息
///void idFind(stu *head); //学号查找学生信息
///void printAll(stu *head); //输出所有学生信息
///void delALl(stu *head); //删除所有学生信息
///void gradeSort(stu *head); //以成绩排序所有学生信息
//声明辅助函数
///bool reId(stu *&head,char *iid); //判断学号是否重复
///void id_check(stu *&p,stu *&head);//检查输入时学号格式
///void grade_check(stu *&a); //检查输入时成绩格式
///int stuLength(stu *head); //求系统中学生信息个数
int reId(stu *&head,stu *&p,char *iid)//输入学号时判断学号是否已经存在,不能存在两个相同的学号
{
//在这个函数的注释里,把p节点叫做“要修改的节点”
//写这个函数的思路就是,遍历链表中除了“要修改的节点”以外的所
//有节点,判断是否查重,但要注意,在新建学生信息时,因为我采
//用的是头插法,所以可以直接从首节点的下一个节点开始遍历链表查
//重;但修改学生信息调用此函数时,要修改的节点不一定是首节点,
//因此查重时要多考虑首节点
stu *q=head->next->next;
if((head->next!=p)&&(strcmp(head->next->id,iid)==0))//修改学生信息时会用到这个代码块,新建时有无此代码块无影响
return 1;//重复了
if(q==p)//修改学生信息时会用到这个代码块,新建时有无此代码块无影响
q=q->next;
while(q!=NULL&&(strcmp(q->id,iid)!=0))//遍历所有信息找学号是否重复
{
if(q->next==p)//修改学生信息时会用到这个代码块,新建时有无此代码块无影响
q=q->next;
q=q->next;
}
if(q!=NULL)
return 1;//重复了
else
return 0;//没重复
}
void id_check(stu *&p,stu *&head)//输入学号时检查是否符合格式
{
int n=0;
while(true)
{
n=0;
if(strlen(p->id)==12)//12位学号
n++;
if(strspn(p->id,"0123456789")==strlen(p->id))//学号中只包含数字
n++;
if(reId(head,p,p->id)==1)//系统中有重复的学号
n--;
if(strcmp(p->id,"000000000000")==0)//不能存在"000000000000"学号,不合常识
n--;
if(n==2)
break;
printf("系统提示:\n学号信息错误,请核对您的学号信息并重新输入:\n");
scanf("%s",p->id);
id_check(p,head);
}
}
void grade_check(stu *&a)//输入成绩是检查是否符合格式
{
stu *p=a;
int b=p->grade;
while((b<0)||(b>100))//合理的成绩区间
{
printf("系统提示:\n成绩格式错误,请重新输入成绩:\n");
scanf("%d",&b);
p->grade=b;
grade_check(p);
}
}
void n_built(stu *&head)//新建学生信息函数
{
stu *p=(stu *)malloc(sizeof(stu));
p->next=head->next;
head->next=p;
printf("请输入学生姓名:");
scanf("%s",p->name);
printf("请输入学生的12位只含数字的学号:");
scanf("%s",p->id);
id_check(p,head);
printf("请输入学生成绩(0-100分):");
scanf("%d",&(p->grade));
grade_check(p);
printf("系统提示:\n新建学生信息成功:\n\t姓名:%s\n\t学号:%s\n\t成绩:%d\n\n",p->name,p->id,p->grade);
}
void printAll(stu *head)//输出所有学生信息
{
stu *p=head->next;
int i=1;
if(p==NULL)
{
printf("系统提示:\n学生信息为空,没有信息需要输出!\n");
return;
}
else
printf("所有学生信息输出如下:\n");
while(p)//p的值不为空就一直循环输出,遍历链表
{
printf("第%d条学生信息:%s\t\t\t%s\t\t\t%d\n",i,p->name,p->id,p->grade);
p=p->next;
i++;
}
printf("\n");
}
void delALl(stu *&head)//删除所有学生信息,遍历链表
{
stu *p=head->next,*q=head;
while(p!=NULL)
{
free(q);
q=p;
p=q->next;
}
free(q);
printf("系统提示:\n所有学生信息为空,删除完成!\n");
}
void modify(stu *&head)//修改学生信息函数
{
char id[ID_MAX];
int flag=0;
int b=0;
stu *p=head->next;
if(p==NULL)
{
printf("系统提示:\n学生信息为空,没有信息可以修改!\n");
return;
}
printf("输入要修改学生的学号:");
scanf("%s",id);
while(p)//如果p的值不为空且没找到要修改的学生信心,一直执行
{
if(!strcmp(id,p->id))
{
flag=1;
printf("请输入新的姓名:");
scanf("%s",p->name);
printf("请输入新的学号(12位):");
scanf("%s",p->id);
id_check(p,head);
printf("请输入新的成绩(0-100):");
scanf("%d",&b);
p->grade=b;
grade_check(p);
printf("学生信息修改成功:%s %s %d\n\n",p->name,p->id,p->grade);
break;
}
p=p->next;
}
if(!flag)
printf("系统提示:\n无此学生相关信息,修改失败!\n\n");
}
void delOne(stu *&head)//通过学号删除指定学生信息
{
char idd[ID_MAX];
int flag=0;
stu *p=head,*q;
if(head->next==NULL)
{
printf("系统提示:\n学生信息为空,没有信息需要删除!\n");
return;
}
printf("输入要删除的学号:");
scanf("%s",idd);
while(p->next)//如果p的值不为空且没找到要删除的学生信息,一直执行
{
if(!strcmp(idd,p->next->id))//找到要删除的学生信息
{
flag=1;
printf("学生信息删除成功:%s %s %d\n\n",p->next->name,p->next->id,p->next->grade);
q=p->next;
p->next=q->next;
free(q);
break;
}
p=p->next;
}
if(!flag)
printf("系统提示:\n无此学生相关信息,删除失败!\n\n");
}
void idFind(stu *head)//通过学号查找学生信息
{
char id[ID_MAX];
int flag=0;
stu *p=head->next;
if(p==NULL)
{
printf("系统提示:\n学生信息为空,查找失败!\n");
return;
}
printf("输入要查找的12位学号:");
scanf("%s",id);
while(p)
{
if(!strcmp(id,p->id))//利用字符串比较函数判断是否找到要查找学号
{
flag=1;
printf("学生信息为:%s %s %d\n\n",p->name,p->id,p->grade);
break;
}
p=p->next;
}
if(!flag)
printf("系统提示:\n无此学生相关信息,查找失败!\n\n");
}
int stuLength(stu *head)//获得学生信息中信息的个数
{
int n=0;
stu *p=head;
while(p->next!=NULL)
{
n++;
p=p->next;
}
return n;
}
void gradeSort(stu *&head)//按成绩排序所有学生信息
{
stu *first,*tail,*p_min,*minn,*p;
first=NULL;//用于排序的临时链表
if(head->next==NULL)
{
printf("系统提示:\n学生信息为空,排序失败!\n");
return;
}
if(stuLength(head)==1)
{
printAll(head);
printf("排序完成!\n");
return;
}
while(head->next!=NULL)
{
for(p=head->next,minn=head->next;p->next!=NULL;p=p->next)
{
if(p->next->grade<minn->grade)
{
p_min=p;//成绩最低指针的前驱结点
minn=p->next;//将成绩最低的指针赋给minn结点
}
}
if(first==NULL)
{
first=minn;
tail=minn;
}
else
{
tail->next=minn;
tail=minn;
}
if(minn==head->next)
head->next=head->next->next;
else
p_min->next=minn->next;
}
if(first!=NULL)
tail->next=NULL;
head->next=first;
printf("排序完成!\n");
}
int main()
{
int choice,n=1;
//system("mode con cols=5 lines=3");
stu *head=(stu *)malloc(sizeof(stu));//动态分配一个stu大小的内存
head->next=NULL;
while(true)
{
printf(" ************************************\n");
printf(" 菜单 \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("请从1,2,3,4,5,6,7这7个数字中选择一个来执行对应功能:");
while(true)//这个while循环只有输入0-7之内的数才会跳出循环,不然会在5次循环后退出
{
scanf("%d",&choice);
if(choice>=0&&choice<=7)
break;
if(n==5)
{
printf("系统提示:\n\t恶意输入!!!\n\t强制退出!!!\n");
choice=0;
break;
}
printf("系统提示:\n无此选项,请从1,2,3,4,5,6,7中选择一项重新输入\n");
n++;
}
if(choice==1)//通过choice的值来执行不同的功能函数
n_built(head);
else if(choice==2)
modify(head);
else if(choice==3)
delOne(head);
else if(choice==4)
idFind(head);
else if(choice==5)
printAll(head);
else if(choice==6)
{
delALl(head);
head->next=NULL;
}
else if(choice==7)
gradeSort(head);
else
return 0;
}
}