基于文件、链表的学生管理系统。将保存和读出分别封装成函数,调用更加方便。
欢迎大家一起交流。
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
typedef unsigned int u32;
typedef unsigned char u8;
typedef struct student//定义一个结构体当做数据域
{
u32 id;
u8 name[20];
u8 sex;
u32 old;
float score;
}STUDENT;
typedef struct list_tag
{
STUDENT stu; //数据域
struct list_tag *pnext; //指针域
}LINK;
//保存表头指针
LINK *phead;
//保存新创建的节点指针
LINK *pnew;
//保存临时节点指针
LINK *ptmp;
LINK *next;
LINK *pdel;
LINK *pins;
FILE *fp;
enum MK
{
add_tag=1,search_tag,del_tag,modify_tag,sort_tag,all_tag,ins_tag,out_tag
};
u32 count=0;
enum MK menu(void);
int creat(void);
int add(void);
void search(void);
void del(void);
int modify(void);
void sort(void);
void all(void);
void ins(void);
int save(void);
int read(void);
void out(void);
int main()
{
if(creat()==0)
{
printf("创建失败\n");
return 0;
}
read();
while(1)
{
switch(menu())
{
case add_tag : add();break;
case search_tag : search();break;
case del_tag : del();break;
case modify_tag : modify();break;
case sort_tag : sort();break;
case all_tag : all();break;
case ins_tag : ins();break;
case out_tag : out();save();return 0;
}
}
return 0;
}
enum MK menu()
{
enum MK num;
printf("----------------------------------\n");
printf("\t%d.增加学生信息\n",add_tag);
printf("\t%d.查找学生信息\n",search_tag);
printf("\t%d.删除学生信息\n",del_tag);
printf("\t%d.修改学生信息\n",modify_tag);
printf("\t%d.排序学生成绩\n",sort_tag);
printf("\t%d.输出所有学生信息\n",all_tag);
printf("\t%d.插入学生信息\n",ins_tag);
printf("\t%d.退出系统\n",out_tag);
printf("----------------------------------\n");
come:
printf("请输入需要的功能前的编号以回车结尾\n");
scanf("%d",&num);
getchar();
if(num<add_tag||num>out_tag)
{
printf("输入错误,请输入正确的编号\n");
goto come;
}
return num;
}
int creat(void)
{
phead=(LINK*)malloc(sizeof(LINK));//malloc函数有一个返回值是void*类型的必须强制转换为link*类型
if(phead==NULL)
{
printf("创建失败\n");
return 0;
}
printf("创建成功\n");
printf("phead= %p\n", phead);
memset(phead,0,sizeof(LINK));
phead->pnext=NULL;//将单链表中第一个节点的指针域指针和数据域指针全部初始化
return 1;
}
int add(void)
{
u32 id=0;
u32 flag=0;
u8 ch;
add2:
pnew=(LINK*)malloc(sizeof(LINK));
if(pnew==NULL)
{
printf("创建失败\n");
return 0;
}
printf("pnew=%p\n", pnew);
memset(pnew,0,sizeof(LINK));
pnew->pnext=NULL;//给新创建的节点指针域清空
printf("输入要添加的学生的学号\n");
scanf("%d", &id);
getchar();
ptmp=phead->pnext;//假设链表已经建立完毕,此时ptmp存放的是首节点的指针域的内容,也就是下一节点的头地址
while(ptmp!=NULL)
{
if(ptmp->stu.id==id)//访问首节点指针域,所存放的下一节点的头地址里面的数据域里面的stu.id。
{
flag=1;
break;
}
ptmp=ptmp->pnext;
}
if(flag==1)
{
printf("此学号已经被别人注册,请重新输入\n");
free(pnew);//删除当前创建的节点。
goto FFFF;
}
pnew->stu.id=id;//此时id的判断已经结束,可以进行后续的输入
printf("请输入添加学生的姓名\n");
scanf("%s", pnew->stu.name);
getchar();
printf("请输入添加学生的性别\n");
scanf("%c", &pnew->stu.sex);
getchar();
printf("请输入添加学生的年龄\n");
scanf("%d", &pnew->stu.old);
printf("请输入添加学生的分数\n");
scanf("%f", &pnew->stu.score);
getchar();
ptmp=phead;
while(ptmp->pnext!=NULL)
{
ptmp=ptmp->pnext;
}
ptmp->pnext=pnew;//倒数第二个节点的,指针域存放新节点的头地址。这样新节点就变成了最后一个节点。
count++;
FFFF:
printf("是否继续添加(Y/N)\n");
ch = getchar();
getchar();
if(ch == 'y' || ch == 'Y')
goto add2;
return 1;
}
void search(void)
{
u32 id=0,flag=0;
u8 ch;
come:
printf("输入你想查询的学生的id\n");
scanf("%d", &id);
getchar();
ptmp=phead->pnext;
while(ptmp!=NULL)
{
if(ptmp->stu.id==id)
{
flag=1;
break;
}
ptmp=ptmp->pnext;
}
if(flag==1)
{
printf("查找学生的信息如下:\n");
printf("姓名:%s\n", ptmp->stu.name);
printf("学号:%d\n", ptmp->stu.id);
printf("性别:%c\n", ptmp->stu.sex);
printf("年龄:%d\n", ptmp->stu.old);
printf("分数:%f\n", ptmp->stu.score);
}
if(flag==0)
{
printf("查无此人\n");
}
printf("是否继续查询(Y/N)\n");
scanf("%c", &ch);
getchar();
if(ch=='Y'||ch=='y')
{
goto come;
}
}
void del(void)
{
u32 flag=0,id;
u8 ch,jc;
tw:
printf("请输入需要删除的学生的id\n");
scanf("%d", &id);
getchar();
ptmp=phead;
while(ptmp->pnext!=NULL)
{
if(ptmp->pnext->stu.id==id)
{
flag=1;
break;
}
ptmp=ptmp->pnext;
}
if(flag==1)
{
pdel=ptmp->pnext;
printf("您要删除的学生信息如下:\n");
printf("姓名:%s\n", pdel->stu.name);
printf("学号:%d\n", pdel->stu.id);
printf("性别:%c\n", pdel->stu.sex);
printf("年龄:%d\n", pdel->stu.old);
printf("分数:%f\n", pdel->stu.score);
printf("请确认是否删除(Y/N)\n");
scanf("%c", &ch);
getchar();
if(ch=='Y'||ch=='y')
{
ptmp->pnext = pdel->pnext;//在删除之前需要将前后连起来
free(pdel);//释放
count--;
printf("删除成功\n");
}
}
else
{
printf("查无此人\n");
}
printf("是否继续删除(Y/N)\n");
scanf("%c", &jc);
getchar();
if(jc == 'Y'|| jc == 'y')
{
goto tw;
}
}
int modify(void)
{
u32 id, flag=0,g;
u32 a,b;//新的学号和年龄
u8 c,ch;//新的性别
u8 D[20];//新的名字
float e;//新的分数
nice:
printf("请输入您要修改的学生的学号\n");
scanf("%d", &id);
getchar();
for(ptmp=phead->pnext;ptmp!=NULL;ptmp=ptmp->pnext)
{
if(ptmp->stu.id==id)
{
flag=1;
break;
}
}
if(flag==0)
{
printf("查无此人\n");
}
if(flag==1)
{
printf("请输入须要修改的学生信息前面的序号\n");
printf("1 修改姓名 2 修改学号\n");
printf("3 修改性别 4 修改年龄\n");
printf("5 修改分数 6 退出\n");
scanf("%d", &g);
getchar();
switch(g)
{
case 1:printf("请输入新姓名\n");
scanf("%s", D);
getchar();
strcpy(ptmp->stu.name,D);
break;
case 2:printf("请输入新学号\n");
scanf("%d", &a);
getchar();
ptmp->stu.id=a;
break;
case 3:printf("请输入心得性别\n");
scanf("%c", &c);
getchar();
ptmp->stu.sex=c;
break;
case 4:printf("请输入新的年龄\n");
scanf("%d", &b);
getchar();
ptmp->stu.old=b;
break;
case 5:printf("请输入新的分数\n");
scanf("%f", &e);
getchar();
ptmp->stu.score=e;
break;
default:
return 1;
}
printf("修改完成,是否继续修改(Y/N)\n");
scanf("%c", &ch);
getchar();
if(ch=='Y'||ch=='y')
{
goto nice;
}
return 1;
}
}
void sort(void)
{
float type;
for(ptmp=phead->pnext;ptmp!=NULL;ptmp=ptmp->pnext)
{
for(next=ptmp->pnext;next!=NULL;next=next->pnext)
{
if(next->stu.score>ptmp->stu.score)
{
type=next->stu.score;
next->stu.score=ptmp->stu.score;
ptmp->stu.score=type;
}
}
}
printf("所有学生成绩排序完毕\n");
}
void all(void)
{
u32 i=0;
for(ptmp=phead->pnext;ptmp!=NULL;ptmp=ptmp->pnext)
{
i++;
printf("第%d名:\n", i);
printf("姓名:%s\n", ptmp->stu.name);
printf("学号:%d\n", ptmp->stu.id);
printf("性别:%c\n", ptmp->stu.sex);
printf("年龄:%d\n", ptmp->stu.old);
printf("分数:%f\n", ptmp->stu.score);
}
}
void ins()
{
u32 id, flag=0,s,flag1=0;
u8 ch;
sss:
printf("请输入要插入节点的位置id\n");
scanf("%d", &id);
getchar();
ptmp=phead->pnext;
while(ptmp!=NULL)
{
if(ptmp->stu.id==id)
{
flag=1;
pins=ptmp;
break;
}
ptmp=ptmp->pnext;
}
if(flag==0)
{
printf("未找到插入位置是否重新查找(Y/y),或者直接插入表结尾(N/n)\n");
ch=getchar();
getchar();
if(ch=='Y'||ch=='y')
{
goto ccc;
}
else
add();
}
else
{
ccc:
printf("请输入要插入的学生的学号\n");
scanf("%d", &s);
getchar();
ptmp=phead->pnext;
while(ptmp!=NULL)
{
if(ptmp->stu.id==s)
{
flag1=1;
break;
}
ptmp=ptmp->pnext;
}
if(flag1==1)
{
printf("学号已经存在请重新输入\n");
goto ccc;
}
else
{
pnew=(LINK*)malloc(sizeof(LINK));
memset(pnew,0,sizeof(LINK));
pnew->pnext=NULL;
pnew->stu.id=s;
printf("请输入添加学生的姓名\n");
scanf("%s", pnew->stu.name);
getchar();
printf("请输入添加学生的性别\n");
scanf("%c", &pnew->stu.sex);
getchar();
printf("请输入添加学生的年龄\n");
scanf("%d", &pnew->stu.old);
printf("请输入添加学生的分数\n");
scanf("%f", &pnew->stu.score);
getchar();
pnew->pnext=pins->pnext;//把前一项指针域的值给新节点的指针域。这样新节点后面的一个节点就与新节点连在一起了。
pins->pnext = pnew;//新节点前一个节点的指针域存上新节点的头指针。这样前一节点和新节点也连在一起了。
count++;
}
}
printf("是否继续插入(y/n)\n");
if(getchar() == 'y')
goto sss;
}
void out(void)
{
printf("欢迎您下次使用,再见\n");
}
int save()
{
u32 i;
fp=fopen("管理系统.txt","w+");
if(fp==NULL)
{
printf("创建失败\n");
perror("fopen");
return -1;
}
//fwrite(&count,sizeof(int),1,fp);
if(fwrite(&count,sizeof(int),1,fp)==0)
{
perror("fwrite");
printf("写入失败\n");
fclose(fp);
return -1;
}
ptmp=phead->pnext;
for(i=0;i<count;i++)
{
printf("%d\n",i);
fwrite(ptmp,sizeof(LINK),1,fp);
ptmp=ptmp->pnext;
}
fclose(fp);
printf("关闭成功\n");
}
int read()
{
u32 i;
fp=fopen("管理系统.txt","r");
if(fp==NULL)
{
printf("创建失败\n");
perror("fopen");
return -1;
}
printf("创建成功\n");
fread(&count,sizeof(int),1,fp);
printf("count=%d", count);
ptmp=phead;
for(i=0;i<count;i++)
{
pnew=(LINK*)malloc(sizeof(LINK));//malloc函数有一个返回值是void*类型的必须强制转换为link*类型
if(pnew==NULL)
{
printf("创建失败\n");
return 0;
}
printf("创建成功\n");
printf("pnew= %p\n", pnew);
memset(pnew,0,sizeof(LINK));
//将单链表中第一个节点的指针域指针和数据域指针全部初始化
fread(pnew,sizeof(LINK),1,fp);
pnew->pnext=NULL;
ptmp->pnext=pnew;
ptmp=ptmp->pnext;
}
fclose(fp);
}