问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

C语言设计一个学生学籍管理系统,要求文件形式保存,且用到链表

发布网友 发布时间:2022-04-15 20:32

我来回答

1个回答

热心网友 时间:2022-04-15 22:01

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//链表结点结构体声明
typedef struct subjects
{
char name[20];
float score;
}sub;

typedef struct student
{
int num;
char name[20];
sub  subject[3];
struct student* next;
}stu,*pstu;

#define SIZE sizeof(stu)

//函数申明
pstu LoadInfo();
void PrintMenu();
pstu AddStu(pstu );
pstu DeleStu(pstu );
pstu RwrStu(pstu );
void FindStu(pstu , char );
void Count(pstu ,char * ,float ,float );
void Rank(pstu ,char * );
void SaveQuit(pstu );

//主函数
int main()

float score1,score2;
char n,j;
char subname[20];
pstu head,ptr;

head = LoadInfo();
ptr = head->next;

//创建菜单,进入选择循环
while(1)
{
PrintMenu();
printf("请输入您的选择编号:");
scanf("%d",&n);
getchar();   
switch(n)
{
case 1: 
{
system("cls");    
j=0;
while(4!=j)   
{
printf("欢迎进入信息管理版块!\n\n");
printf("\025 1、添加学生\n");
printf("\025 2、删除学生\n");
printf("\025 3、修改学生信息\n");
printf("\025 4、返回\n");
printf("请输入您的选择编号:\n");
scanf("%d",&j);
getchar();

if     ( 1 == j) head = AddStu(head);
else if( 2 == j) head = DeleStu(head);
else if( 3 == j) head = RwrStu(head);
else if( 4 == j) ;
else printf("输入有误,请重新输入!\n");

}
printf("请输入回车键返回主菜单!");     //此处本意按任意键返回,但是任意键的话,需要按键A,再按回车确定
getchar();//则会连续收到两个按键,造成错误读入,可以改进scanf接收字符串,
system("cls");//以下所有getchar()、system("cls")同理
break;
}
case 2:
{
//信息查询
system("cls");
printf("欢迎进入信息查询版块!\n");
printf("请输入要查询的学生编号:");
scanf("%d",&j);
getchar();
//printf("%d\n",j);   //检测输入是否成功,调试程序用
FindStu(head,j);    //查询并输出
printf("\n请输入回车键返回主菜单!");
getchar();
system("cls");
break;
}
case 3:
{
//成绩统计
system("cls");
printf("欢迎进入成绩统计版块!\n");
printf("请输入科目:");
scanf("%s",&subname);
getchar();
printf("请输入分数范围(score1,score2):");
scanf("%f,%f",&score1,&score2);
getchar();
/*printf("%s %5.2f %5.2f\n",subname,
 score1,score2);   */          //检测输入是否成功,调试程序用
Count(head,subname,score1,score2);      //统计并输出
printf("请输入回车键返回主菜单!");
getchar();
system("cls");
break;
}
case 4:
{
//成绩排序
system("cls");
printf("欢迎进入成绩排序版块,请输入科目:");
scanf("%s",&subname);
getchar();
Rank(head,subname);  //排序并输出
printf("\n请输入回车键返回主菜单!\n");
getchar();
system("cls");
break;
}
case 5:
{
//保存退出
SaveQuit(head);//文件操作,保存并退出
free(head);
return 0;
}
default: 
{
printf("输入有误,按回车键重新选择!\n");//主菜单错误输出检测
getchar();
system("cls");
}
}
}

  
}

//加载data数据 ,文件操作
pstu LoadInfo()
{
int   num;
char name[20];
char sub1[20];
char sub2[20];
char sub3[20];
float score1;
float score2;
float score3;

char filename[] = "D:\\编程学习\\编程实践\\c语言课程设计1 学生信息管理\\data.txt";  //文件名,此处为简化编程,采用固定地址名称,未作输入
   FILE *fp; 
pstu head,ptr;

//创建带表头结点的空单链表head,用来存放载入信息
head = (pstu)malloc(SIZE);
ptr = head;
ptr->next = NULL;


//加载data文件,存入head链表
if( NULL == (fp = fopen(filename,"r")) ) //判断文件是否存在及可读

printf("error!"); 
exit(0); 


while (!feof(fp)) 

fscanf(fp,"%d %s %s %f %s %f %s %f\n",&num,&name,
  &sub1,&score1,&sub2,&score2,&sub3,&score3); //读取一行,采用格式化读取,避免了其他各种读取方法的数据处理问题
//该方法缺点明显,对数据格式要求教研,故data文件规定数据格式
ptr->next = (pstu)malloc(SIZE);
ptr = ptr->next;
ptr->next = NULL;

ptr->num = num;
strcpy(ptr->name,name);
strcpy(ptr->subject[0].name,sub1);
ptr->subject[0].score = score1;
strcpy(ptr->subject[1].name,sub2);
ptr->subject[1].score = score2;
strcpy(ptr->subject[2].name,sub3);
ptr->subject[2].score = score3;



    fclose(fp);                     //关闭文件,已得到保存data信息的链表head

return head;
}


//打印主菜单
void PrintMenu()    
{
printf("***************************************\n");
printf("           枫枫学生信息管理系统        \n");
printf("***************************************\n");
putchar('\n');
printf("菜单\n");
printf("\025 1、信息管理\n");
printf("\025 2、信息查询\n");
printf("\025 3、成绩统计\n");
printf("\025 4、成绩排序\n");
printf("\025 5、保存退出\n");
}

//添加学生
pstu AddStu(pstu x)  
{
char namestu[20];
char *p;
char subname1[20],subname2[20],subname3[20];
pstu head,ptr;

head = x;
ptr = head;

while( NULL != ptr->next )//遍历链表,找到链尾结点
{
ptr = ptr->next;
}

ptr->next = (pstu)malloc(SIZE);//默认在链表末追加添加信息
ptr = ptr->next;
ptr->next = NULL;

printf("请输入添加学生的信息:\n");

printf("请输入添加学生的学号:");
scanf("%d",&ptr->num);
getchar();

printf("请输入添加学生的姓名:");
scanf("%s",namestu);
getchar();
p = namestu;
strcpy(ptr->name,p);

printf("请输入添加学生的科目1名称:");
scanf("%s",&subname1);
getchar();
p = subname1;
strcpy(ptr->subject[0].name,p);

printf("请输入添加学生的科目1成绩:");
scanf("%f",&ptr->subject[0].score);
getchar();

printf("请输入添加学生的科目2名称:");
scanf("%s",&subname2);
getchar();
p = subname2;
strcpy(ptr->subject[1].name,p);

printf("请输入添加学生的科目2成绩:");
scanf("%f",&ptr->subject[1].score);
getchar();

printf("请输入添加学生的科目3名称:");
scanf("%s",&subname3);
getchar();
p = subname3;
strcpy(ptr->subject[2].name,p);

printf("请输入添加学生的科目3成绩:");
scanf("%f",&ptr->subject[2].score);
getchar();

putchar('\n');
return head;
}

//删除学生
pstu DeleStu(pstu x)   
{
int num;
pstu head,ptr,qtr;

head = x;
ptr = head->next;
qtr = head;

printf("请输入要删除的学生的学号:");
scanf("%d",&num);
getchar();

while(ptr!=NULL)
{
if( ptr->num != num)//遍历查找链表结点,未找到跳过该结点
{
ptr = ptr->next;
qtr = qtr->next;
}
else//找到则删除结点
{
ptr = ptr->next;
qtr->next = ptr;
break;
}
}

printf("该学生信息已删除!\n\n");
return head;
}

//修改学生信息
pstu RwrStu(pstu x)   
{
char namestu[20];
char *p;
char subname1[20],subname2[20],subname3[20];
int num;
pstu head,ptr;

head = x;
ptr = head->next;

printf("请输入要修改的学生的学号:");
scanf("%d",&num);
getchar();

while(ptr!=NULL)
{
if( ptr->num == num )
{
printf("已找到该学生信息,请填入修改项目:");

printf("请输入修改学生的姓名:");
scanf("%s",namestu);
getchar();
p = namestu;
strcpy(ptr->name,p);

printf("请输入修改学生的科目1名称:");
scanf("%s",subname1);
getchar();
p = subname1;
strcpy(ptr->subject[0].name,p);

printf("请输入修改学生的科目1成绩:");
scanf("%f",&ptr->subject[0].score);
getchar();

printf("请输入修改学生的科目2名称:");
scanf("%s",subname2);
getchar();
p = subname2;
strcpy(ptr->subject[1].name,p);

printf("请输入修改学生的科目2成绩:");
scanf("%f",&ptr->subject[1].score);
getchar();

printf("请输入修改学生的科目3名称:");
scanf("%s",subname3);
getchar();
p = subname3;
strcpy(ptr->subject[2].name,p);

printf("请输入修改学生的科目3成绩:");
scanf("%f",&ptr->subject[2].score);
getchar();

printf("该学生信息已修改!\n\n");
break;
}
else
{
ptr = ptr->next;
}
}

return head;
}

//查找学生,参数为链表指针,和学生学号
//不好,应该将学号输入放进子函数,简化主函数结构,减少子函数参数
void FindStu(pstu x,char y)    
{
pstu head,ptr;

head = x;
ptr = head->next;

while( ptr != NULL)
{
if( ptr->num == (int)y)//因主函数中为节省空间,学号输入采用char数据,故强行准换
{
printf("已找到该学生信息!\n如下:");
printf("%03d  %s  %s  %5.2f  %s  %5.2f  %s  %5.2f\n",
ptr->num,ptr->name,ptr->subject[0].name,ptr->subject[0].score,ptr->subject[1].name,ptr->subject[1].score,ptr->subject[2].name,ptr->subject[2].score);break;//注意此处找到并输出信息后要手动退出循环
}
else
{
ptr = ptr->next;
}
}
if( ptr == NULL )//查询成功检测,while循环中若找到,则ptr停留在当前学生的结点上
{
printf("未能找到该学生信息!\n");
}
}


//统计科目分数区间段的学生,参数为链表指针,科目名称,分数区间上下限
//同理,参数的录入应放入子函数,简化结构和编程
void Count(pstu x,char *y,float q,float p)    
{
pstu head,ptr;
char name[20];
char flag=0;       //手动设置的查找结果flag

head = x;
ptr = head->next;
strcpy(name,y);

//printf("%s %5.2f %5.2f\n",name,q,p); //检测输入参数的传递,调试程序用

while( ptr != NULL)//开始查找统计,科目查找用strcmp函数比较科目字符串,返回值0为字符串相等
{//此处while循环体中,重复的查找步骤太多,应设置科目匹配flag,参照rank()函数
if( strcmp(name,ptr->subject[0].name) == 0 ) //通过flag将科目确认放在while之外,循环体内只做分数区间的扫描和输出
{
if( q <= ptr->subject[0].score && ptr->subject[0].score<= p )
{
printf("%03d  %s  %s  %5.2f\n",ptr->num,ptr->name,ptr->subject[0].name,ptr->subject[0].score);
flag++;
}
}
if( strcmp(name,ptr->subject[1].name) == 0 )
{
if( q <= ptr->subject[1].score && ptr->subject[1].score<= p )
{
printf("%03d  %s  %s  %5.2f\n",ptr->num,ptr->name,ptr->subject[1].name,ptr->subject[1].score);
flag++;
}
}
if( strcmp(name,ptr->subject[2].name) == 0 )
{
if( q <= ptr->subject[2].score && ptr->subject[2].score<= p )
{
printf("%03d  %s  %s  %5.2f\n",ptr->num,ptr->name,ptr->subject[2].name,ptr->subject[2].score);
flag++;
}
}

ptr = ptr->next;
}

if(flag==0)
{
printf("未能找到该课程该区间分数段的学生!\n");
}
}


//学科成绩排名,采用交换数据的方法,参数为链表指针,科目名称
//同理参数问题
//链表排序问题,此处用交换结点数据方法,还有其他多种排序方法
//如,交换结点,辅助指针数组排序(未实现,过程繁杂),插入法排序等
void Rank(pstu x,char *y)     
{
pstu head,ptr,qtr;
char name[20];
char len=0;
char flag=0;    //简化算法,设置科目查找结果判断值,flag=0表示科目输入为未知科目,不存在
int i=0;//i、j循环次数控制参数
int j=0;  
char temp_name[20];//数据交换时的暂存信息变量
float temp0,temp1,temp2;
int temp_num;

strcpy(name,y);
head = x;

ptr = head->next;
while( ptr != NULL)   //测链表长度,不包括表头结点
{
ptr = ptr->next;
len++;
}
ptr = head->next;  //指针ptr用过之后记得回原位


//开始查找科目
if( strcmp(name,ptr->subject[0].name) == 0)flag=1; 
if( strcmp(name,ptr->subject[1].name) == 0)flag=2;
if( strcmp(name,ptr->subject[2].name) == 0)flag=3;
if( flag == 0)
{
printf("未找到该科目!");
return;
}

//开始排序,冒泡法比较各结点数据
//此处3个并列的if用switch case更清晰结构
if( n == 1 )
{
for( i=0;i<len;i++)
{
ptr = head->next->next;//每一次内循环之后,ptr、qtr必然在最后两个节点上
qtr = head->next;//故在进行内循环之前,要重新复位ptr、qtr
for( j=0;j<len-i-1;j++)
{
if( qtr->subject[0].score < ptr->subject[0].score )
{
temp_num = qtr->num;//交换数据,因数据格式(科目顺序)明确规定,故不再做科目名称的替换
strcpy(temp_name,qtr->name);
temp0 = qtr->subject[0].score;
temp1 = qtr->subject[1].score;
temp2 = qtr->subject[2].score;

qtr->num = ptr->num;
strcpy(qtr->name,ptr->name);
qtr->subject[0].score = ptr->subject[0].score;
qtr->subject[1].score = ptr->subject[1].score;
qtr->subject[2].score = ptr->subject[2].score;

ptr->num = temp_num;
strcpy(ptr->name,temp_name);
ptr->subject[0].score = temp0;
ptr->subject[1].score = temp1;
ptr->subject[2].score = temp2;
}
qtr = qtr->next;
ptr = ptr->next;
}
}
}

if( n == 2 )
{
for( i=0;i<len;i++)
{
ptr = head->next->next;
qtr = head->next;
for( j=0;j<len-i-1;j++)
{
if( qtr->subject[1].score < ptr->subject[1].score )
{
temp_num = qtr->num;
strcpy(temp_name,qtr->name);
temp0 = qtr->subject[0].score;
temp1 = qtr->subject[1].score;
temp2 = qtr->subject[2].score;

qtr->num = ptr->num;
strcpy(qtr->name,ptr->name);
qtr->subject[0].score = ptr->subject[0].score;
qtr->subject[1].score = ptr->subject[1].score;
qtr->subject[2].score = ptr->subject[2].score;

ptr->num = temp_num;
strcpy(ptr->name,temp_name);
ptr->subject[0].score = temp0;
ptr->subject[1].score = temp1;
ptr->subject[2].score = temp2;
}
qtr = qtr->next;
ptr = ptr->next;
}
}
}

if( n == 3 )
{
for( i=0;i<len;i++)
{
ptr = head->next->next;
qtr = head->next;
for( j=0;j<len-i-1;j++)
{
if( qtr->subject[2].score < ptr->subject[2].score )
{
temp_num = qtr->num;
strcpy(temp_name,qtr->name);
temp0 = qtr->subject[0].score;
temp1 = qtr->subject[1].score;
temp2 = qtr->subject[2].score;

qtr->num = ptr->num;
strcpy(qtr->name,ptr->name);
qtr->subject[0].score = ptr->subject[0].score;
qtr->subject[1].score = ptr->subject[1].score;
qtr->subject[2].score = ptr->subject[2].score;

ptr->num = temp_num;
strcpy(ptr->name,temp_name);
ptr->subject[0].score = temp0;
ptr->subject[1].score = temp1;
ptr->subject[2].score = temp2;
}
qtr = qtr->next;
ptr = ptr->next;
}
}
}

//输出排序过后的链表
ptr = head->next;
while( ptr != NULL )
{
printf("%03d  %s  %s  %5.2f  %s  %5.2f  %s  %5.2f\n",
  ptr->num,ptr->name,ptr->subject[0].name,ptr->subject[0].score,
  ptr->subject[1].name,ptr->subject[1].score,
  ptr->subject[2].name,ptr->subject[2].score);
ptr = ptr->next;
}
}


//保存文件并退出,文件操作
void SaveQuit(pstu x)    
{
pstu head,ptr;
FILE *fp;
char filename[] = "D:\\编程学习\\编程实践\\c语言课程设计1 学生信息管理\\data.txt";
head = x;
ptr = head->next;

if( NULL == (fp = fopen(filename,"w")) ) //判断文件是否存在及可读

printf("error!"); 
exit(0); 


while(ptr != NULL)//遍历链表结点,按data约定格式输出数据
{
fprintf(fp,"%03d  %s  %s  %5.2f  %s  %5.2f  %s  %5.2f\r",
ptr->num,ptr->name,ptr->subject[0].name,ptr->subject[0].score,

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...A.任何物体,只要其两端电势差不为零,就有电流存在 B.闭合... 在下身高183cm体重53kg怎么锻炼才能使肌肉迅速增长 农行k宝换了收款方全部没有了 ...弄丢了,完了又在农行办了一个新的k宝,办了新k宝以后是不是以前的... 比如说我在A地办了个k宝,但是要求外地,且不会回A地了,我把A地的银行卡... AI里面怎么内容转成JPG不清楚? 电脑待机时间长了屏幕就会一闪一闪的,不停的跳。。。这是怎么回事儿... 电脑开机和待机之后的一段时间屏幕闪烁 电脑待机一段时间后出现如图情况一直闪 重启下就没事 好可怕 大神求... 为何电脑待机时间长了就像死机主机灯还在闪? talk talk english怎么说 talk发音 报考安徽三支一扶需要什么条件么? 三支一扶的报名条件? 三支一扶指的是什么 怎么考? 应聘简历中计算机技能怎么写? 计算机专业技能怎么写啊 报考2021年安徽三支一扶考试,需要满足哪些条件? 三支一扶中支教有什么要求? 2022年三支一扶报考条件是什么? 普通南孚电池可以再次充电使用吗?谢谢了,大神帮忙啊 南孚电池如何二次充电?操作流程? 南孚电池在什么上面用过后可以再用 一节5号南孚电池,怎么让它持续放电。 ICU什么意思?胃出血拉血意思是大便时发现粪便里有血就去医院检查,医生... 普通南孚电池可以再次充电使用吗?求大神帮助 刚买了一个南孚电池,现在要把里面的电用完再充,还是充满了再用 南孚电池是否可以用6次? IUC是什么意思? 普通南孚电池可以再次充电使用吗?谢谢了,大神帮忙啊两个电池要充多少分钟 梦见父亲光着身子躺在床上,怎么叫都叫不醒 梦见自己看到父亲光着全身用刀割他自己脚上的毒瘤是什么意思? 范进中举句子赏析 可以放在饭卡套里的照片是多大的 怎样用word打印出饭卡大小的照片? 梦见健在的父亲光着身子躺在冰冷的地上 写出范进中举中的5个夸张句子.并点评. 怎么才能把学校饭卡上的照片弄褪色 范进中举 赏析 饭卡上的照片可以留刘海嘛? 饭卡上的照片能不能换掉,跪求方法 问《范进中举》的赏析!!高手快快来! 梦见已故的父亲光着全身拿着西瓜? 谁可以。给我看一下上大饭卡照片 范进中举 课文赏析 梦见过逝的爸爸在很脏的厕所里,厕所里还有内脏。而且爸爸光着身子身上都是冰,是怎么了? 研究生饭卡照片是报名照片吗 《范进中举》第五段的赏析 梦见梦见已过世的父母光着身子睡觉 饭卡上的照片会出现在哪些地方