学习了一个月的C语言开始动手写一篇学生成绩管理系统博客
结构体的定义及节点的构成
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct student
{
int num;
char name[20];
char sex[10];
char xueyuan[20];
char banji[20];
int math;
int cyuyan;
int english;
int zongfen;
struct student *next;
}STU;
下面为函数的声明部分
void show();//菜单函数
int *create(STU *head);//录入学生函数
bool add(STU*head);//增加学生信息
int bianli(STU *head);//打印学生信息函数
int fangzhichongfu(STU*head,int n);//防止录入同学号
int find(STU *head);//查找函数
int mondify(STU *head);//修改函数
int shanchu(STU * head);//删除函数
int average(STU *head);//求单科平均分函数
void paixu(STU *head);//单科排序函数
void save(STU*head);//文件保存 功能
STU * duqu(STU *head);//文件的读取
int fangzhifushu(int b);//防止分数与学号为负数
先进入函数的功能实现吧
先简单来个菜单显示功能
void show()
{
system("cls");
printf("*----------------------------------------------------*\n");
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("* 8: 读取信息到系统 *\n");
printf("* 9: 保存信息到文件 *\n");
printf("* 10: 插入学生信息 *\n");
printf("* 0: 按0退出系统 *\n");
printf("*----------------------------------------------------*\n");
printf("选择操作<0-10> \n");
return;
}
功能一实现链表的创立即学生信息的录入这个是有一个头指针然后顶一个tail指针作为尾巴,因为我是尾插法做链表然后tail的指针域指向下一个节点,然后下一个节点变成tail依次插入学生信息
int *create(STU *head)//输入学生信息;//该函数会从面函数中传输过来一个头结点,该节点无数据只有指针域。
{
int m;//因为我的录入函数是while循环来做的我想设置一个终止录入的小零件。
STU *tail=head;//定义一个结构体函数使其指向头结点
while(tail->next!=NULL)
{
tail=tail->next;
}
while(1)
{
STU*p=(STU*)malloc(sizeof(STU));//每次都申请一个空间用于接收下一个学生信息
if(p==NULL)
{
printf("创建失败\n"); //如果申请空间失败终止函数
return 0;
}
int h;//这里有个小细节goto如果输入的非整形的数据则h!=1;goto函数我也不太懂在网上看的。
tt:printf("请输入学号\n");
h=scanf("%d",&p->num);
if(h!=1)
{fflush(stdin);
goto tt;
}
long int c=fangzhifushu(p->num);
if(c==0)
{printf("学号不能为负\n");
continue;
}
int b=fangzhichongfu(head,p->num);
if(b==0)
{printf("输入学号重复请重输入");
continue;
}
printf("请输入姓名");
scanf("%s",p->name);
printf("请输入性别仅限 nan代表*男* nv代表*女* 不介意的话可以加入其它种类\n");
char j[4]={"nan"};//先定义俩个字符串nan,nv,当满足输入的sex为nan或者nv时才会通过,性别只有男女的情况下
char q[3]={"nv"};
while(1)
{
scanf("%s",p->sex);
if(!strcmp(p->sex,j))
{break;}
else if(!strcmp(p->sex,q))
{break;}
else
{printf("你输入了新物种请重新输入\n");
continue;}
}
printf("请输入学院\n");
scanf("%s",p->xueyuan);
printf("请输入班级\n");
scanf("%s",p->banji);
while(1)
{
int hh;
ccg:printf("请输入数学成绩\n");
hh=scanf("%d",&p->math);
if(hh!=1)
{fflush(stdin);
goto ccg;
}
int ma=fangzhifushu(p->math);
if(ma==0)
{
printf("数学成绩不能为负请重新输入\n");
continue;
}
break;
}
while(1)
{
int hhh;
ccgg:printf("请输入C语言成绩\n");
hhh=scanf("%d",&p->cyuyan);
if(hhh!=1)
{fflush(stdin);
goto ccgg;
}
int cyu=fangzhifushu(p->cyuyan);
if(cyu==0)
{
printf("c语言成绩不能为负请重新输入\n");
continue;
}
break;
}
while(1)
{
int hhhh;
ccggg:printf("请输入英语成绩\n");
hhhh=scanf("%d",&p->english);
if(hhhh!=1)
{fflush(stdin);
goto ccggg;
}
int eng=fangzhifushu(p->english);
if(eng==0)
{
printf("英语成绩不能为负请重新输入\n");
continue;
}
break;
}
p->zongfen=p->math+p->cyuyan+p->english; //总分计算
p->next=NULL;//初始化指针
tail->next=p;
tail=p; //使tail变成尾节点为链接下一个节点准备
printf("录入结束按0 继续录入按1:\n");
getchar();
scanf("%d",&m);//跳出录入函数的小零件
if(m==0)
break;
}
printf("录入学生信息完毕\n");
}
下一个功能为遍历链表链表的遍历没啥说的就是依次打印学生信息
int bianli(STU *head)
{
STU *p=head->next;
if(p==NULL)
printf("暂无学生信息请指令功能一后调用此功能\n");
while(p)
{
printf("学号:%d\t 姓名:%s\t 性别:%s\t 学院:%s\t 班级:%s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t 总分:%d\t \n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english,p->zongfen);
p=p->next;
}
system("pause");
return 0;
}
查询函数该函数实现了学号查询,班级查询,学院查询功能
查询功能是利用if语句找到索要查询的信息
int find(STU *head)
{
while(1)
{
STU *q;
q=head->next;
if(q==NULL){printf("暂无学生信息请指令功能一后调用此功能\n");}
printf(" 欢迎进入查询菜单 \n");
printf("*********************************************************\n");
printf("* 指令1:按学号查询 *\n");
printf("* 指令2:按班级查询 *\n");
printf("* 指令3:按学院查询 *\n");
printf("********************************************************\n\n");
int r;
printf("请输入查询功能指令");
scanf("%d",&r);
if(r==1)//分功能式查询
{
printf("输入查询的学号\n");
int i;
scanf("%d",&i);
while(q)
{
if(i==q->num)
{
printf("学号:%d\t 姓名 %s\t 性别:%s\t 学院 %s\t 班级 %s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t 总分:%d\t \n",q->num,q->name,q->sex,q->xueyuan,q->banji,q->math,q->cyuyan,q->english,q->zongfen);
}
q=q->next;
}break;
}
else if(r==2)
{
printf("请输入查询学生的班级\n");
char dd[20];
scanf("%s",dd);
while(q)
{
if(!strcmp(q->banji,dd))
{
printf("学号:%d\t 姓名 %s\t 性别:%s\t 学院 %s\t 班级 %s\n数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t 总分:%d\t \n",q->num,q->name,q->sex,q->xueyuan,q->banji,q->math,q->cyuyan,q->english,q->zongfen);
}
q=q->next;
}break;
}
else if(r==3)
{
printf("请输入查询学生的学院\n");
char cc[20];
scanf("%s",cc);
while(q)
{
if(!strcmp(q->xueyuan,cc))
{
printf("学号:%d\t 姓名 %s\t 性别:%s\t 学院 %s\t 班级 %s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t 总分:%d\t \n",q->num,q->name,q->sex,q->xueyuan,q->banji,q->math,q->cyuyan,q->english,q->zongfen);
}
q=q->next;
}break;
}
else
{
printf("输入指令错误\n");
system("pause");
continue;
};
}
printf("查无此人\n");
system("pause");
}
来到了修改学生信息功能修改没啥好说的看代码就可以了解了
int mondify(STU *head)//修改函数
{
bianli(head);
if(head->next==NULL)
return 0;
printf("查看你所要修改的学生后可进行修改\n");
STU *w,*q;
q=head->next;
w=head->next;
if(w==NULL)
{
printf("暂无学生信息请指令功能一后调用此功能\n");
return 0;
}
int flag,x;
printf("输入所需修改学生的学号\n");
scanf("%d",&x);
//=(STU*)malloc(sizeof(STU));
while(w!=NULL&&w->num!=x)
w=w->next;
if(w!=NULL)
{
while(1)
{
printf("\n修改学号: 修改姓名: 修改性别: 学院: 班级:成绩: 数学成绩: C语言成绩: 英语成绩:\n");
printf("按2修改学号: 按3修改姓名:按4修改性别: 按5修改学院:\n按6修改班级:按7修改数学成绩1:按8修改C语言成绩: 按9修改英语成绩:\n");
printf("如需修改全部信息请安1\n");
scanf("%d",&flag);
if(flag==1)
{
printf("请重新输入学号\n");
scanf("%d",&w->num);
printf("请重新输入名字");
scanf("%s",w->name);
printf("请输入性别仅限 nan代表*男* nv代表*女* 不介意的话可以加入其它种类\n");
char bn[4]={"nan"};
char mn[3]={"nv"};
while(1)
{
scanf("%s",w->sex);
if(!strcmp(w->sex,bn))
{break;}
else if(!strcmp(w->sex,mn))
{break;}
else
{printf("你输入了新物种请重新输入\n");
continue;}
}
printf("请重新输入学院\n");
scanf("%s",w->xueyuan);
printf("请重新输入班级\n");
scanf("%s",w->banji);
while(1)
{
printf("请输入数学成绩\n");
scanf("%d",&w->math);
int ma=fangzhifushu(w->math);
if(ma==0)
{
printf("数学成绩不能为负请重新输入\n");
continue;
}
break;
}
while(1)
{
printf("请输入C语言成绩\n");
scanf("%d",&w->cyuyan);
int cyu=fangzhifushu(w->cyuyan);
if(cyu==0)
{
printf("c语言成绩不能为负请重新输入\n");
continue;
}
break;
}
while(1)
{
printf("请输入英语成绩\n");
scanf("%d",&w->english);
int eng=fangzhifushu(w->english);
if(eng==0)
{
printf("英语成绩不能为负请重新输入\n");
continue;
}
break;
}
break;
}
if(flag==2)
{
printf("重新输入学号:");
int xuehao;
while(q)
{
scanf("%d",&xuehao);
if(xuehao==q->num)
{
printf("学号重复,重新输入\n");
system("pause");
continue;
}
else
{
q=q->next;
}
}
w->num=xuehao;
break;
}
else if(flag==3)
{
printf("请重新输入姓名");
scanf("%s",&w->name[20]);
break;
}
else if(flag==4)
{
printf("兄弟长这么大我还是头一次听说修改性别\n重新输入性别\n");
scanf("%s",&w->sex[10]);
break;
}
else if(flag==5)
{
printf("请重新输入学院");
scanf("%s",&w->xueyuan[20]);
break;
}
else if(flag==6)
{
printf("请重新输入班级");
scanf("%s",&w->banji);
break;
}
else if(flag==7)
{
printf("请重新输入数学成绩");
scanf("%d",&w->math);
break;
}
else if(flag==8)
{
printf("请输入C语言的成绩");
scanf("%d",&w->cyuyan);
break;
}
else if(flag==9)
{
printf("请重新输入英语成绩");
scanf("%d",&w->english);break;
}
else
printf("输入的修改信息不存在请重新输入指令\n");
}
}
system("pause");
}
接着我们来删除功能
删除功能大概是先遍历链表找到删除的链表节点然后使其前一个节点的指针域直接指向删除节点的后面一个节点然后释放删除的节点
int shanchu(STU * head)//删除功能
{
bianli(head);
if(head->next==NULL)
return 0;
printf("找到你所要删除的学生执行删除功能\n");
STU *k,*y;
printf("请输入删除学生的学号");
k=head->next;
y=head;
int n;
scanf("%d",&n);
while(k)
{
if(n==k->num)
{
int bbbb;
printf("是否确认删除该学生按1取消 任意键确定");
scanf("%d",&bbbb);
if(bbbb==1)
return 0;
y->next=k->next;//让y的指针域直接指向下下个节点相当于跳过一个节点保证了链表的连续
free(k);//释放了该节点删除学生信息;
k=NULL;
printf("删除成功\n");
system("pause");
return 0;
}
y=k;
k=k->next;
}
printf("查无此人\n");
system("pause");
}
增加学生信息这个图是基本原理让新申请的空间指针域指向所要插入点的前方,然后在让前一个学生节点的指针域指向新学生的节点!
bool add(STU*head)
{
char name1[20],xueyuan1[20],banji1[20],sex1[10];
int num1,math1,cyuyan1,english1;
int n;
STU *q;
q=head->next;
int index=0;
printf("请输入要增加的学生信息和位置;\n");
printf("请输入学生信息;\n");
printf("学号:");
while(q){
scanf("%d",&num1);
fflush(stdin);
if(num1==q->num)
{
printf("输入学号重复,请重新输入");
continue;
}
break;
}
printf("姓名:");
scanf("%s",name1);
printf("性别:");
scanf("%s",sex1);
printf("学院:");
scanf("%s",xueyuan1);
printf("班级");
scanf("%s",banji1);
printf("数学成绩:");
scanf("%d",&math1);
printf("C语言成绩");
scanf("%d",&cyuyan1);
printf("英语成绩");
scanf("%d",&english1);
printf("请输入需要增加的位置:");
scanf("%d",&n);
STU*r;
STU*p=head;
if(n<=0)
{
return false;
}
while(p)
{
index++;
if(n==index)
{
r=(STU*)malloc(sizeof(STU));
strcpy(r->name,name1);
strcpy(r->sex,sex1);
strcpy(r->xueyuan,xueyuan1);
strcpy(r->banji,banji1);
r->num=num1;
r->math=math1;
r->cyuyan=cyuyan1;
r->english=english1;
r->zongfen=num1+cyuyan1+english1;
r->next=p->next;//这个地方是插入的重要步骤先让新创建的空间指向所要插入位置的后一个节点
p->next=r;//再让前一个节点指向新插入的节点即可完成插入
printf("添加成功!\n");
return true;
}
p=p->next;
}
return false;
}
排序功能是我这个小白当时看了好久才略懂一些,这个地方需要深究,我是用冒泡排序来做排序功能的,可能有更好的方法求大佬指教。.
void paixu(STU *head)
{
int pai;
printf("请输入按分数排序的学科\n按1为数学\t按2为c语言\t按3为英语\t按4为总分排序\n");
STU *p,*q,*r;//定义三个指针其中r相当于交换时的容器。
p=head;
q=head->next;
scanf("%d",&pai);
if(pai==1)//数学的排序
{
if(p->next==NULL){
printf("无学生信息");
system("pause");
return ;}
while(p->next!=NULL)
{
while(q->next!=NULL)
{
if(p->next->math<q->next->math)
{
r=p->next;//
p->next=q->next;//
q->next=q->next->next;
p->next->next=r;
}
else
{
q=q->next;
}
}
p=p->next;
q=p->next;
}
p=head->next;
printf("按数学排名如下");
while(p)
{
printf("学号:%d\t 姓名:%s\t 性别:%s\t 学院:%s\t 班级:%s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t \n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english);
p=p->next;
}
}
if(pai==2)//C语言的排序
{
if(p->next==NULL){
printf("无学生信息");
system("pause");
return ;}
while(p->next!=NULL)
{
while(q->next!=NULL)
{
if(p->next->cyuyan<q->next->cyuyan)
{
r=p->next;
p->next=q->next;
q->next=q->next->next;
p->next->next=r;
}
else
{
q=q->next;
}
}
p=p->next;
q=p->next;
}
p=head->next;
printf("按C语言排名如下");
while(p)
{
printf("学号:%d\t 姓名:%s\t 性别:%s\t 学院:%s\t 班级:%s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t \n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english);
p=p->next;
}
}
if(pai==3)//英语的排序
{
if(p->next==NULL){
printf("无学生信息");
system("pause");
return ;}
while(p->next!=NULL)
{
while(q->next!=NULL)
{
if(p->next->english<q->next->english)
{
r=p->next;
p->next=q->next;
q->next=q->next->next;
p->next->next=r;
}
else
{
q=q->next;
}
}
p=p->next;
q=p->next;
}
p=head->next;
printf("按英语排名如下");
while(p)
{
printf("学号:%d\t 姓名:%s\t 性别:%s\t 学院:%s\t 班级:%s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t \n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english);
p=p->next;
}
}
if(pai==4)//总分 排序
{
while(p->next!=NULL)
{
while(q->next!=NULL)
{
if(p->next->zongfen<q->next->zongfen)
{
r=p->next;
p->next=q->next;
q->next=q->next->next;
p->next->next=r;
}
else
{
q=q->next;
}
}
p=p->next;
q=p->next;
}
p=head->next;
printf("按总分排名如下");
while(p)
{
printf("学号:%d\t 姓名:%s\t 性别:%s\t 学院:%s\t 班级:%s\n 数学成绩:%d\t C语言成绩:%d\t 英语成绩:%d\t 总分:%d\t \n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english,p->zongfen);
p=p->next;
}
}
system("pause");
}
关于文件的功能直接上格式吧格式写上就明白了很多了
信息输入完成后可以将其保存到电脑文件中,保存时可以保存两个文件,一个放数据便于读取到程序,一个放数据和学生信息便于观看
读取时读取只函数据那个文件,不然读取文件会崩溃,因为读取时不能读取文字信息。这点需要注意
void save(STU*head)//保存
{
STU* p;
FILE* fp;
FILE* fp1;
if((fp=fopen("li.txt","w+"))==NULL)
{
printf("文件打开失败\n");
}
else
{
p=head->next;
while(p!=NULL)
{
fprintf(fp,"学号:%d 姓名:%s 性别:%s 学院:%s 班级:\n%s 数学:%d C语言:%d 英语:%d 总分:%d\n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english,p->zongfen);
p=p->next;
}
}
if((fp1=fopen("li1.txt","w+"))==NULL)
{
printf("文件打开失败\n");
}
else
p=head->next;
{
while(p!=NULL)
{
fprintf(fp1,"%d %s %s %s %s %d %d %d %d\n"
,p->num,p->name,p->sex,p->xueyuan,p->banji,p->math,p->cyuyan,p->english,p->zongfen);
p=p->next;
}
}
printf("保存成功\n");
fclose(fp);
fclose(fp1);
system("pause");
}
//*****************************************************************************************************************************
STU *duqu(STU *head)
{
STU *pnew=NULL;
FILE *fileopen=NULL;
fileopen=fopen("li1.txt","r");
if(fileopen==NULL)
{
printf("\n不能打开文件\n");
system("pause");
return 0;
}
while(1){
pnew=(STU *)malloc(sizeof(STU));
if(pnew==false)
{
printf("\n内存申请失败!!!\n");
}
if(fscanf(fileopen,"%d %s %s %s %s %d %d %d %d\n"
,&pnew->num,pnew->name,pnew->sex,pnew->xueyuan,pnew->banji,&pnew->math,&pnew->cyuyan,&pnew->english,&pnew->zongfen)==EOF){
break;
}
pnew->next=NULL;
head->next=pnew;
head=pnew;
}
fclose(fileopen);
printf("读取成功");
system("pause");
return head;
}
别的都是一些小功能了
比如防止学号重复函数和防止分数为负数函数
int fangzhichongfu(STU*head,int n)//防止学号重复
{
STU *ss;
int a=n;
ss=head->next;
while(ss)
{
if(ss->num==a)
{
return 0;
}
ss=ss->next;
}
return 1;
}
int fangzhifushu(int b)//防止学号为负数
{
int d=b;
if(d<0)
{return 0;}
return 1;
}
面函数的实现,有个很废的登录系统没啥用可以忽略l
另外菜单功能最好用字符型来写,不然无法防止乱输系统崩溃。
int main()
{
system("color f9");
printf("请注册一个账号\n");
char zhanghao[20];
scanf("%s",zhanghao);
int zhengquemima;
printf("请输入注册密码");
scanf("%d",&zhengquemima);
printf("你有三次登录密码的机会\n");
for(int cishu=0;cishu<3;cishu++)
{ int mima;
printf("请输入密码\n");
scanf("%d",&mima);
if(mima==zhengquemima)
{
STU * head=(STU *)malloc(sizeof(STU));head->next=NULL;
while(1)
{ show();
char select[128];//调用菜单功能定义为字符串类型防止乱输崩溃。
printf("请输入调用功能");
scanf("%s",select);
int a=strlen(select);
if(a<2)
{
switch(select[0])
{
case '1':system("cls");create(head);break;
case '2':system("cls");shanchu(head);break;
case '3':system("cls");mondify(head);break;
case '4':system("cls");bianli(head);break;
case '5':system("cls");find(head);break;
case '6':system("cls");average(head);break;
case '7':system("cls");paixu(head);break;
case '8':system("cls");duqu(head);break;
case '9':system("cls");save(head);break;
case '0':system("cls");return 0;
}
}
else if(a>=2&&a<=3)
{
switch(select[0]+select[1])
{
case 'a':system("cls");add(head);break;
default:system("cls");printf("输入指令错误\n");system("pause");break;
}
}
else if(a>3)
{
printf("指令错误\n");
system("pause");
}
}
}
}
printf("三次都没输对退出系统");
return 0;
}
总结
提示:这里对文章进行总结:
我还是个小菜比,希望以后写代码漏洞会少一些另外这个文章还有很多需要补充的东西,等回头会再来补充。