计算机实习报告
姓名:王方正
学号:20174314
一、开发任务
题目源自《程序设计实践教程》教材22题,学生基本信息管理。描述略。
二、需求分析
1.说明自己针对这个任务将完成哪些功能的设计。
学生基本信息管理任务的基本功能是:
(1)从文件中读取学生记录
(2)新增学生记录
(3)编辑学生记录各个字段
(4)删除指定学生记录
(5)按指定字段查询并显示学生详细信息
(6)按指定功能统计并显示
2.说明程序将会具有什么样的性能:
程序中有如下性能:
(1)提供精美菜单供用户选择对应功能
(2)提供详细输入提示帮助用户正确输入信息
(3)提供强力的边界保护防止非法数据影响数据库学生记录的存储使用
(4)提供身份码验证,管理员与普通用户两套身份码,管理员具有对记录增、删、改、查的权限,普通用户只具有查的权限,无身份码用户无法实用程序,身份码有试错次数限制,超出试错次数限制直接关闭程序
(5)提供即时回退机制,在任意界面,按照输入提示输入制定内容均可回退至上级菜单
(6)提供数据回显,在修改学生数据时,即时回显修改后的学生记录,便于用户进一步操作,提供良好的交互体验
(7)提供良好的统计展示,统计量为0的不必要值不会展示,优化用户查阅统计结果的体验
三、程序设计
针对需求做如下设计:
1. 数据结构设计
假设学生记录的数据结构是:学号(主键)、姓名、专业、生源地、民族、性别、政治面貌、家庭收入、学生入学4科成绩
struct Student { int num;//学号 char name[10];//姓名 char major[20];//专业 char origin[8];//生源地 char ethnic[12];//民族 char sex[3];//性别 char politic[12];//政治面貌 double income;//家庭收入 double score[4];//学生成绩,score[0]~score[3]分别对应语文成绩、数学成绩、英语成绩、综合成绩 };
2. 模块设计
本系统主要提供从文件中读取学生记录、新增学生记录、编辑学生记录各个字段、删除指定学生记录、按指定字段查询并显示学生详细信息、按指定功能统计并显示的功能,下面按模块说明其实现:
从文件中读取学生记录:通过Initialize_Student()获得外存文件路径,通过Load_Student()将外存文件中学生记录读入内存结构体中。
新增学生记录:通过New_Student()调用Get系函数,获得输入学生记录的各个字段并进行边界判定,将合法的学生记录信息存取内存结构体中
编辑学生记录各个字段:通过Check_Name()按姓名查找学生记录,并展示所有同名学生记录详细信息,通过Check_Number()供用户选择同名学生记录中的制定学生记录,通过Show_Student()展示数据,并展示选择待修改的字段菜单,并在每次修改结束后通过Show_Student()再次展示数据,达到数据的回显。
删除指定学生记录:通过Delete_Student()将指定位置后的所有学生记录前移一个位置,覆盖待删除学生记录。
按指定字段查询并显示详细信息:通过Menu_Check()展示选择待查询字段的菜单,用户选择待查询字段,调用Check系函数,按指定字段查询,并显示符合合法输入的全部学生记录的详细信息。
按指定功能统计并显示的功能:通过Menu_Count()展示选择统计功能,用户选择统计功能,先按实现功能必须进行制定字段调用Sort系函数进行快速排序,然后调用Count系函数实现制定功能。
3. 主程序结构
本任务的主程序结构是登陆界面,用户输入身份码,验证正确则转入对应身份的主菜单中,用户在主菜单选择对应功能,转入相应的子程序中。
四、程序实现
(1)void Print_Welcome()
输 入:无
输 出:无
返回值:无
功 能:在控制台打印欢迎字符画。
void Print_Welcome() { printf("\t\t\t\t _______ _ _______ _______ _______ _______ \n"); printf("\t\t\t\t|\\ /|( ____ \\( \\ ( ____ \\( ___ )( )( ____ \\\n"); printf("\t\t\t\t| ) ( || ( \\/| ( | ( \\/| ( ) || () () || ( \\/\n"); printf("\t\t\t\t| | _ | || (__ | | | | | | | || || || || (__ \n"); printf("\t\t\t\t| |( )| || __) | | | | | | | || |(_)| || __) \n"); printf("\t\t\t\t| || || || ( | | | | | | | || | | || ( \n"); printf("\t\t\t\t| () () || (____/\\| (____/\\| (____/\\| (___) || ) ( || (____/\\\n"); printf("\t\t\t\t(_______)(_______/(_______/(_______/(_______)|/ \\|(_______/\n\n"); }
(2)void Printf_End()
输 入:无
输 出:无
返回值:无
功 能:在控制台结束字符画的打印。
void Print_End()//结束程序彩蛋 { system("color fc"); printf("\t\t\t\t _______ _______ _______ ______ ______ _______ \n"); printf("\t\t\t\t( ____ \\( ___ )( ___ )( __ \\ ( ___ \\ |\\ /|( ____ \\\n"); printf("\t\t\t\t| ( \\/| ( ) || ( ) || ( \\ )| ( ) )( \\ / )| ( \\/\n"); printf("\t\t\t\t| | | | | || | | || | ) || (__/ / \\ (_) / | (__ \n"); printf("\t\t\t\t| | ____ | | | || | | || | | || __ ( \\ / | __) \n"); printf("\t\t\t\t| | \\_ )| | | || | | || | ) || ( \\ \\ ) ( | ( \n"); printf("\t\t\t\t| (___) || (___) || (___) || (__/ )| )___) ) | | | (____/\\\n"); printf("\t\t\t\t(_______)(_______)(_______)(______/ |/ \\___/ \\_/ (_______/\n"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 感谢使用!! │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); }
(3)int Length_Student(Student data[])
输 入:保存所有学生记录的结构体data
输 出:无
返回值:结构体中学生记录的个数
功能:实现计算结构体中记录个数。保存所有学生记录的结构体data作为形参输入,若记录中的学号字段不为0,计数器自增。返回值为结构体中记录的个数。
int Length_Student(Student data[])//结构体长度 { int i;//循环用变量 for(i=0;data[i].num!=0;i++); return i; }
(4)void Load_Student(Student data[],FILE *fp)
输 入:保存所有学生记录的结构体data,以只读方式打开文件的文件指针fp
输 出:无
返回值:无
功 能:实现从外存文件将所有学生记录读入内存结构体。保存所有学生记录的结构体data、以只读方式打开文件的文件指针fp作为形参输入,文件到达底部之前,循环将外存文件中的学生记录读入内存结构体中。
void Load_Student(Student data[],FILE *fp)//从文件读取学生信息 { for(int i=0;!feof(fp);i++)//在文件到底之前,将文件中所有记录依次读入 { fscanf(fp,"%d",&data[i].num); fscanf(fp,"%s",data[i].name); fscanf(fp,"%s",data[i].major); fscanf(fp,"%s",data[i].origin); fscanf(fp,"%s",data[i].ethnic); fscanf(fp,"%s",data[i].sex); fscanf(fp,"%s",data[i].politic); fscanf(fp,"%lf",&data[i].income); fscanf(fp,"%lf",&data[i].score[0]); fscanf(fp,"%lf",&data[i].score[1]); fscanf(fp,"%lf",&data[i].score[2]); fscanf(fp,"%lf",&data[i].score[3]); } fclose(fp);//关闭文件 }
(5)void Overwrite_Student(Student data[],FILE *fp)
输 入:保存所有学生记录的结构体data,以只写方式打开文件的文件指针fp
输 出:无
返回值:无
功 能:实现从内存结构体将所有学生记录写入外存文件。保存所有学生记录的结构体data、以只写方式打开文件的文件指针fp作为形参输入,调用Length_Student函数获得结构体中学生记录条数,循环将内存结构体中的学生记录写入外存文件中。
void Overwrite_Student(Student data[],FILE *fp)//覆盖文件中的记录 { for(int i=0;i
(6)void Initialize_Student(Student data[])
输 入:保存所有学生记录的结构体data,外存文件路径address
输 出:无
返回值:无
功 能:实现内存结构体的初始化。保存所有学生记录的结构体data作为形参输入。输入外存文件路径address,若输入-1,退出程序。若文件打开成功,调用Load_Student将学生记录从外存文件读入内存结构体,将address储存在结构体中有学生记录的末尾的下一个位置,方便文件路径在函数间传递,同时不会影响正常学生记录的存储读取。
void Initialize_Student(Student data[])//初始化结构体 { system("cls"); char address[20];//记录文件名的字符串 FILE *fp=NULL;//文件指针置空 printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 选择文件路径 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t请输入文件路径(完整路径,输入-1退出程序):"); scanf("%s",address); if(strcmp(address,"-1")==0)//输入-1退出程序 { system("cls");//清屏 Print_End();//展示结束画面 exit(0);//关闭程序 } else if((fp=fopen(address, "a"))==NULL)//无法打开文件,递归重新输入文件名 { printf("\n\t\t\t\t文件打开失败...\n\t\t\t\t"); system("pause"); Initialize_Student(data);//递归重新输入文件名 return; } else//文件打开成功 { printf("\n\t\t\t\t文件打开成功!"); system("pause"); fp=fopen(address, "r"); Load_Student(data,fp);//从文件中读取记录到内存中的结构体 strcpy(data[Length_Student(data)].major,address);//利用结构体的末尾存储空间存储文件名字符串 } }
(7)void Get_Number(Student *data,Student stu[])
输 入:临时保存学生记录的结构体指针*data,保存所有学生记录的结构体stu,学生学号
输 出:无
返回值:无
功 能:实现获得输入学生学号及边界判断。临时保存学生记录的结构体指针*data,保存所有学生记录的结构体stu作为形参输入。声明整形变量tmp临时保存输入学生学号。使用fflush(stdin)清除缓冲区,输入学生学号。若学生学号为-1,将tmp临时保存的值传入data*对应结构体的学号字段。若学生学号不为-1,判断若学生学号对应年级超出合法范围,提示错误,递归获得学生学号。若学生学号对应年级符合合法范围,遍历stu,若输入学号与stu中学号重复,提示错误,递归获得学生学号。若学生学号不与stu中的任何一个学生记录的学生学号重复,将tmp临时保存的值传入*data对应的结构体的学号字段。通过一系列判断,最终将合法学生学号或-1传入*data对应的结构体的学号字段,实现了输入的边界判断。
void Get_Number(Student *data,Student stu[])//获取学号的函数,前者为临时结构体,后者为已录入外存记录的结构体 { printf("\t\t\t\t请输入学号(八位数字,输入-1返回上级菜单):"); int tmp=-2;//临时变量,保存输入值,置为非法置,防止输入字符时错误跳转 int length=Length_Student(stu);//计算结构体总长度 fflush(stdin);//清空缓存区 scanf("%d",&tmp); if(tmp!=-1)//输入-1,返回上级菜单 { if(tmp/10000<1977||tmp/10000>2020)//超出学生年级范围 { printf("\t\t\t\t学号输入错误!\n"); Get_Number(data,stu);//递归 return;//函数此处结束 } for(int i=0;i<=length;i++)//在原学号库中查重 { if(stu[i].num==tmp)//输入学号重复 { printf("\t\t\t\t学号输入重复!\n"); Get_Number(data,stu);//递归 return;//函数此处结束 } } } data->num=tmp;//最终将合法值或-1传入临时结构体 return; }
(8)void Get_Name(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生姓名
输 出:无
返回值:无
功 能:实现获得输入学生姓名及边界判断。临时保存学生记录的结构体指针*data作为形参传入。声明字符串tmp临时保存输入学生姓名。输入学生姓名。若学生姓名为-1,将tmp临时保存的值传入*data对应结构体的姓名字段。若学生姓名不为-1,通过strlen获得输入学生姓名长度,按位比对tmp中每个位置的ASCII码值,若任意一个字符ACSII值的范围在1~127之外,即任意字符非英文、数字、标点符号,则学生姓名输入正确,将tmp临时保存的值*data对应的结构体的姓名字段。否则提示错误,递归获得学生姓名。通过一系列判断,最终将合法学生姓名或-1传入*data对应的结构体姓名字段,实现了输入的边界判断。
void Get_Name(Student *data) { printf("\t\t\t\t请输入姓名(中文名,输入-1返回上级菜单):"); char tmp[10];//临时变量,保存输入值 scanf("%s",tmp); int length=strlen(tmp);//获取字符串长度 if(strcmp(tmp,"-1")!=0)//输入-1,返回上级菜单 { for(int i=0;i<=length;i++) { if(tmp[i]>=1&&tmp[i]<=127)//如果输入了非中文字符,判断为输入错误 { printf("\t\t\t\t姓名输入错误!\n"); Get_Name(data); return; } } } strcpy(data->name,tmp);//将合法值传入临时结构体 return; }
(9)void Get_Major(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生专业
输 出:无
返回值:无
功 能:实现获得输入学生专业及边界判断。临时保存学生记录的结构体指针*data作为形参传入。声明整型变量flag指示专业,是否存在,初始值置0。声明字符串tmp临时保存输入学生专业。声明二维字符数组majorlist,储存所有合法学生专业。输入学生专业。若学生专业为-1,将tmp临时保存的值传入*data对应结构体的专业字段。若学生专业不为-1,顺序比对输入学生专业与majorlist中合法专业,若输入专业合法,flag置1,停止比对。若flag为1,将tmp临时保存的值传入*data对应的结构体的专业字段。若flag为0提示错误,递归获得学生专业。通过一系列判断,最终将合法学生专业或-1传入*data对应的结构体专业字段,实现了输入的边界判断。
void Get_Major(Student *data) { printf("\t\t\t\t请输入专业\n\t\t\t\t(信息与计算科学/信息安全/计算机科学与技术/信息管理与信息系统/电子信息工程/通信工程/行政管理/保密管理,输入-1返回上级菜单):"); int flag=0;//指示专业是否存在 char tmp[20];//临时变量,保存输入值 char majorlist[8][20]={"信息与计算科学","信息安全","计算机科学与技术","信息管理与信息系统","电子信息工程", "通信工程","行政管理","保密管理"};//比对专业信息的库 scanf("%s",tmp); if(strcmp(tmp,"-1")!=0)//输入-1,返回上级菜单 { for(int i=0;i<8;i++) if(strcmp(tmp,majorlist[i])==0) { flag=1; break; } if(flag==0)//没有找到库中的专业 { printf("\t\t\t\t专业输入错误!\n"); Get_Major(data);//递归 return; } } strcpy(data->major,tmp); return; }
(10)void Get_Origin(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生生源地
输 出:无
返回值:无
功 能:实现获得输入学生生源地及边界判断。具体实现思路与Get_Major基本一致。
void Get_Origin(Student *data) { printf("\t\t\t\t请输入生源地(省份名称,输入-1返回上级菜单):"); int flag; char tmp[8]; char originlist[34][8]={"北京","天津","上海","重庆","河北","山西","辽宁","吉林","黑龙江", "江苏","浙江","安徽","福建","江西","山东","河南","湖北","湖南","广东","海南","四川","贵州", "云南","陕西","甘肃","青海","台湾","内蒙古","广西","西藏","宁夏","新疆","香港","澳门"}; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { for(int i=0;i<34;i++) if(strcmp(tmp,originlist[i])==0) { flag=1; break; } if(flag==0)//没有找到库中的省份 { printf("\t\t\t\t生源地输入错误!\n"); Get_Origin(data);//递归 return; } } strcpy(data->origin,tmp); return; }
(11)void Get_Sex(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生性别
输 出:无
返回值:无
功 能:实现获得输入学生性别及边界判断。具体实现思路与Get_Major基本一致。
void Get_Sex(Student *data) { printf("\t\t\t\t请输入性别(男/女,输入-1返回上级菜单):"); char male[3]="男",female[3]="女",tmp[3]; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { if(strcmp(tmp,male)*strcmp(tmp,female)!=0)//如果输入的性别不是男或女中的任一个,输入错误 { printf("\t\t\t\t性别输入错误!\n"); Get_Sex(data); return; } } strcpy(data->sex,tmp); return; }
(12)void Get_Ethnic(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生民族
输 出:无
返回值:无
功 能:实现获得输入学生民族及边界判断。具体实现思路与Get_Major基本一致。
void Get_Ethnic(Student *data) { printf("\t\t\t\t请输入民族(民族名称,输入-1返回上级菜单):"); int flag=0; char tmp[12]; char ethniclist[56][12]={"汉族","蒙古族","回族","藏族","维吾尔族","苗族","彝族","壮族", "布依族","朝鲜族","满族","侗族","瑶族","白族","土家族","哈尼族","哈萨克族","傣族","黎族", "僳僳族","佤族","畲族","高山族","拉祜族","水族","东乡族","纳西族","景颇族","柯尔克孜族", "土族","达斡尔族","仫佬族","羌族","布朗族","撒拉族","毛南族","仡佬族","锡伯族","阿昌族", "普米族","塔吉克族","怒族","乌孜别克族","俄罗斯族","鄂温克族","德昂族","保安族","裕固族", "京族","塔塔尔族","独龙族", "鄂伦春族","赫哲族","门巴族","珞巴族","基诺族"}; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { for(int i=0;i<57;i++) if(strcmp(tmp,ethniclist[i])==0){ flag=1; break; } if(flag==0) { printf("\t\t\t\t民族输入错误!\n"); Get_Ethnic(data);//递归 return; } } strcpy(data->ethnic,tmp); return; }
(13)void Get_Politic(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生政治面貌
输 出:无
返回值:无
功 能:实现获得输入学生政治面貌及边界判断。具体实现思路与Get_Major基本一致。
void Get_Politic(Student *data) { printf("\t\t\t\t请输入政治面貌\n\t\t\t\t(群众/无党派人士/共青团员/入党积极分子/中共预备党员/中共党员,输入-1返回上级菜单):"); int flag=0; char tmp[20]; char politiclist[6][20]={"群众","无党派人士","共青团员","入党积极分子","中共预备党员","中共党员"}; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { for(int i=0;i<8;i++) if(strcmp(tmp,politiclist[i])==0) { flag=1; break; } if(flag==0) { printf("\t\t\t\t政治面貌输入错误!\n"); Get_Politic(data);//递归 return; } } strcpy(data->politic,tmp); return; }
(14)void Get_Income(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生家庭收入
输 出:无
返回值:无
功 能:实现获得输入学生家庭收入及边界判断。临时保存学生记录的结构体指针*data作为形参传入。声明双精度浮点变量tmp临时保存输入学生家庭收入,初始置非法值,防止输入字符时将初始化的错误合法值传入,无法提示错误。使用fflush(stdin)清除缓冲区,输入学生家庭收入。若输入-1,将tmp临时保存的值传入*data对应结构体的家庭收入字段。若输入不为-1,判断tmp临时保存的学生家庭收入是否属于合法范围(0~99999),若输入合法,将tmp临时保存的值传入*data对应结构体的家庭收入字段。否则提示错误,递归获得学生家庭收入。通过一系列判断,最终将合法学生家庭收入或-1传入*data对应的结构体家庭收入字段,实现了输入的边界判断。
void Get_Income(Student *data) { printf("\t\t\t\t请输入家庭收入(0~99999,输入-1返回上级菜单):"); double tmp=-2;//初始值非法值,防止输入字符产生错误 fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>=100000)//输入的家庭收入超出范围 { printf("\t\t\t\t家庭收入输入错误!\n"); Get_Income(data); return; } } data->income=tmp; }
(15)void Get_Chinese(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生语文成绩。
输 出:无
返回值:无
功 能:实现获得输入学生语文成绩及边界判断。具体实现思路与Get_Income基本一致。
void Get_Chinese(Student *data) { printf("\t\t\t\t请输入语文成绩(0~150,输入-1返回上级菜单):"); double tmp=-2;//初始置非法值 fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>150) { printf("\t\t\t\t语文成绩输入错误!\n"); Get_Chinese(data); return; } } data->score[0]=tmp; }
(16)void Get_Math(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生数学成绩
输 出:无
返回值:无
功 能:实现获得输入学生数学成绩及边界判断。具体实现思路与Get_Income基本一致。
void Get_Math(Student *data) { printf("\t\t\t\t请输入数学成绩(0~150,输入-1返回上级菜单):"); double tmp=-2; fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>150){ printf("\t\t\t\t数学成绩输入错误!\n"); Get_Math(data); return; } } data->score[1]=tmp; }
(17)void Get_English(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生英语成绩
输 出:无
返回值:无
功 能:实现获得输入学生英语成绩及边界判断。具体实现思路与Get_Income基本一致。
void Get_English(Student *data) { printf("\t\t\t\t请输入英语成绩(0~150,输入-1返回上级菜单):"); double tmp=-2; fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>150){ printf("\t\t\t\t英语成绩输入错误!\n"); Get_English(data); return; } } data->score[2]=tmp; }
(18)void Get_Compre(Student *data)
输 入:临时保存学生记录的结构体指针*data,学生综合成绩
输 出:无
返回值:无
功 能:实现获得输入学生综合成绩及边界判断。具体实现思路与Get_Income基本一致。
void Get_Compre(Student *data) { printf("\t\t\t\t请输入综合成绩(0~300,输入-1返回上级菜单):"); double tmp=-2; fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>300) { printf("\t\t\t\t综合成绩输入错误!\n"); Get_Compre(data); return; } } data->score[3]=tmp; }
(19)void New_Student(Student *data,Student stu[])
输 入:临时保存学生记录的结构体指针*data,保存所有学生记录的结构体stu,所有学生记录字段
输 出:无
返回值:无
功 能:实现新建学生记录,并存入保存所有学生记录的结构体stu的末尾。临时保存学生记录的结构体指针*data,保存所有学生记录的结构体stu作为形参输入。临时保存学生记录的结构体指针*data,保存所有学生记录的结构体stu作为形参输入。依次调用Get_学生记录字段()函数,修改*data对应结构体的字段,并每次进行判断,若*data中字段为-1,调用Menu_Admin()返回管理员主菜单。若新学生记录所有字段均成功录入,将stu的中保存的外部文件路径向后移动一个位置,将*data对应的结构体中临时保存的学生记录置入stu中保存外部文件路径的签一个位置。提示用户是否继续新建学生记录,若“是”,递归继续新建学生记录;若“否”调用Menu_Admin()返回管理员主菜单。
void New_Student(Student *data,FILE *fp,Student stu[])//添加新的学生记录 { int length=Length_Student(stu);//计算内存结构体记录个数 system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 新建学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Get_Number(data,stu);//获得学号,函数将临时结构体data中的num字段改为-1或合法值 if(data->num==-1) Menu_Admin(stu);//若临时结构体data中的num字段为-1,调用函数返回上级菜单 //若临时结构体data中的num字段为合法值,进入程序继续获得下一个字段的值 Get_Name(data); if(strcmp(data->name,"-1")==0) Menu_Admin(stu); Get_Major(data); if(strcmp(data->major,"-1")==0) Menu_Admin(stu); Get_Sex(data); if(strcmp(data->sex,"-1")==0) Menu_Admin(stu); Get_Origin(data); if(strcmp(data->origin,"-1")==0) Menu_Admin(stu); Get_Ethnic(data); if(strcmp(data->ethnic,"-1")==0) Menu_Admin(stu); Get_Politic(data); if(strcmp(data->politic,"-1")==0) Menu_Admin(stu); Get_Income(data); if(data->income==-1) Menu_Admin(stu); Get_Chinese(data); if(data->score[0]==-1) Menu_Admin(stu); Get_Math(data); if(data->score[1]==-1) Menu_Admin(stu); Get_English(data); if(data->score[2]==-1) Menu_Admin(stu); Get_Compre(data); if(data->score[3]==-1) Menu_Admin(stu); strcpy(stu[length+1].major,stu[length].major);//将之前存放的文件名置入结构体末的下一个位置 stu[Length_Student(stu)]=*data;//将新的记录从临时结构体data中置入原结构体stu末 printf("\t\t\t\t是否继续录入?(Y/N)"); char key; getchar();//从键盘读取字符,保证key正常录入 scanf("%c",&key); if(key=='Y') New_Student(data,fp,stu);//递归 else Menu_Admin(stu);//返回上级菜单 }
(20)void Delete_Student(Student data[],int i)
输 入:保存所有学生记录的结构体stu,待删除学生记录位置i
输 出:无
返回值:无
功 能:实现删除学生记录。保存所有学生记录的结构体stu,待删除学生记录位置i作为形参输入。提示是否确认删除。确认删除将stu中i位置后的所有学生记录前移,覆盖i位置的学生记录。成功删除后,调用Menu_Admin()返回管理员主菜单。
void Delete_Student(Student data[],int i)//删除学生档案记录 { printf("\n\t\t\t\t确认删除?(Y/N)"); char ch; Student tmp;//临时结构体,传入更改学生档案函数,用于临时记录修改值 getchar();//清空字符缓冲区 scanf("%c",&ch); if(ch=='Y') { for(int j=i;j
(21)void Change_Student(Student data,Student stu[],int i)
输 入:待修改的保存所有学生记录的结构体stu,学号查重的保存所有学生记录的结构体stu,待修改学生记录位置i
输 出:无
返回值:无
功 能:实现修改学生记录。待修改的保存所有学生记录的结构体stu,学号查重的保存所有学生记录的结构体stu,待修改学生记录位置i作为形参输入,其中stu,data指向同一内存空间。展示菜单,输入菜单选项,选择修改的字段,调用Get_学生记录字段,修改data的对应字段,非法输入递归重新输入菜单选项。
void Change_Student(Student data,Student stu[],int i)//修改学生信息 { printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #1.修改学号字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #2.修改姓名字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #3.修改专业字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #4.修改民族字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #5.修改生源地字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #6.修改性别字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #7.修改政治面貌字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #8.修改家庭收入字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #9.修改语文成绩字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #10.修改数学成绩字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #11.修改英语成绩字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #12.修改综合成绩字段 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #0.返回上级菜单 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t请键入功能编号:"); int key=-1;//初始置非法值,防止输入字符产生错误 fflush(stdin);//清空缓存区 scanf("%d",&key); switch(key) { case 0: Menu_Change(data,stu,i);//取消修改操作,返回删除/更改子菜单,选择删除或更改的操作 case 1: Get_Number(&data,stu);//复用,获得学号 if(data.num!=-1) stu[i].num=data.num; break; case 2:Get_Name(&data); if(strcmp(data.name,"-1")!=0) strcpy(stu[i].name,data.name); break; case 3: Get_Major(&data); if(strcmp(data.major,"-1")!=0) strcpy(stu[i].major,data.major); break; case 4: Get_Ethnic(&data); if(strcmp(data.ethnic,"-1")!=0) strcpy(stu[i].ethnic,data.ethnic); break; case 5: Get_Origin(&data); if(strcmp(data.origin,"-1")!=0) strcpy(stu[i].origin,data.origin); break; case 6: Get_Sex(&data); if(strcmp(data.sex,"-1")!=0) strcpy(stu[i].sex,data.sex); break; case 7: Get_Politic(&data); if(strcmp(data.politic,"-1")!=0) strcpy(stu[i].politic,data.politic); break; case 8: Get_Income(&data); if(data.income!=-1) stu[i].income=data.income; break; case 9: Get_Chinese(&data); if(data.score[0]!=-1) stu[i].score[0]=data.score[0]; break; case 10: Get_Math(&data); if(data.score[1]!=-1) stu[i].score[1]=data.score[1]; break; case 11: Get_English(&data); if(data.score[2]!=-1) stu[i].score[2]=data.score[2]; break; case 12: Get_Compre(&data); if(data.score[3]!=-1) stu[i].score[3]=data.score[3]; break; default: printf("输入错误!");//非法输入的提示 Change_Student(data,stu,i);//递归跳转 break; } }
(22)void Show_Student(Student data[],int i)
输 入:保存所有学生记录的结构体data,待展示学生记录的位置i
输 出:指定位置学生记录的详细信息
返回值:无
功 能:实现展示指定位置学生记录详细信息。保存所有学生记录的结构体data,待展示学生记录的位置i作为形参输入。在控制台展示stu中i位置学生记录的详细信息。
void Show_Student(Student data[],int i)//展示学生全部信息 { printf("#####################################################################################################################################\n"); printf("\t学号:%d\t\t姓名:%s\t\t年级:%d\t\t班级:%d\t\t专业:%s\n", data[i].num,data[i].name,data[i].num/10000,data[i].num/100,data[i].major); printf("\t生源地:%s\t\t民族:%s\t\t性别:%s\t\t家庭收入:%.0lf\t\t政治面貌:%s\n" ,data[i].origin,data[i].ethnic,data[i].sex,data[i].income,data[i].politic); printf("\t语文成绩:%.1lf\t\t数学成绩:%.1lf\t\t英语成绩:%.1lf\t\t综合成绩:%.1lf\t\t总分:%.1lf\n", data[i].score[0],data[i].score[1],data[i].score[2],data[i].score[3], data[i].score[0]+data[i].score[1]+data[i].score[2]+data[i].score[3]); printf("#####################################################################################################################################\n\n"); }
(23)void Sort_Number(Student data[],int front,int rear)
输 入:保存所有学生记录的结构体data
输 出:无
返回值:无
功 能:实现对所有学生记录按学号由小至大进行快速排序。
void Sort_Number(Student data[],int front,int rear)//对全部学生信息按学号快速排序 { if(front>=rear) { return; } int i=front; int j=rear; Student tmp=data[front];//轴 while(i=data[i].num)//找比轴大的记录 { i++; } data[j]=data[i];//放到轴后面 } data[i]=tmp;//轴置入中间 Sort_Number(data,front,i-1);//轴的前一半,递归 Sort_Number(data,i+1,rear);//轴的后一半,递归 }
(24)void Sort_Origin(Student data[],int front,int rear)
输 入:保存所有学生记录的结构体data
输 出:无
返回值:无
功 能:实现对所有学生记录按生源地进行快速排序。
void Sort_Origin(Student data[],int front,int rear)//对全部学生信息按生源地快速排序 { if(front>=rear) { return; } int i=front; int j=rear; Student tmp=data[front]; while(i=0) { i++; } data[j]=data[i]; } data[i]=tmp; Sort_Origin(data,front,i-1); Sort_Origin(data,i+1,rear); }
(25)void Sort_Ethnic(Student data[],int front,int rear)
输 入:保存所有学生记录的结构体data
输 出:无
返回值:无
功 能:实现对所有学生记录按民族进行快速排序。
void Sort_Ethnic(Student data[],int front,int rear)//对全部学生信息按民族快速排序 { if(front>=rear) { return; } int i=front; int j=rear; Student tmp=data[front]; while(i=0) { i++; } data[j]=data[i]; } data[i]=tmp; Sort_Ethnic(data,front,i-1); Sort_Ethnic(data,i+1,rear); }
(26)void Sort_Major(Student data[],int front,int rear)
输 入:保存所有学生记录的结构体data
输 出:无
返回值:无
功 能:实现对所有学生记录按专业进行快速排序。
(27)int Check_Number(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查学号
输 出:无
返回值:待查学号在data中的位置或-1
功 能:实现按学号查找学生记录。保存所有学生记录的结构体data,指示上级菜单的menuflag作为形参输入。输入待查学号,若输入为-1,函数返回-1。若输入不为-1,用二分法对学号进行查找,若找到返回学号对应学生记录的位置。若未找到,声明整形变量check记录内层函数的返回值,递归继续查找学号,函数返回check。通过一系列判断,函数最终返回合法待查询学号在stu中的位置或-1。
(28)void Check_Name(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查姓名
输 出:符合待查姓名的所有学生记录
返回值:无
功 能:实现按姓名查找学生记录。保存所有学生记录的结构体data,指示上级菜单的menuflag作为形参输入。声明整形变量flag指示是否找到待查记录,初始值置0。输入待查姓名,若输入为-1,依照menuflag指示调用函数返回上级菜单:若menuflag为1,调用Menu_Admin()返回管理员主菜单,若menuflag为0,调用Menu_User()返回用户主菜单。
若输入姓名不为-1,遍历data,若找到符合待查姓名的学生记录,flag置1,调用Show_Student展示学生记录详细信息。若flag最终为0,提示未找到符合待查姓名的学生记录,递归继续查找。
(29)void Check_Grade(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查年级
输 出:符合待查年级的所有学生记录
返回值:无
功 能:实现按年级查找学生记录。具体实现思路与Check_Name()基本一致,其中年级的通过数学方法获得。如:
int num=20174301; int grade=num/10000; //grade=2017
(30)void Check_Class(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查班级
输 出:符合待查班级的所有学生记录
返回值:无
功 能:实现按班级查找学生记录。具体实现思路与Check_Name()基本一致,其中班级的通过数学方法获得。如:
int num=20174301; int classnum=(num/100)%10000; //classnum=1743
(31)void Check_Major(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查专业
输 出:符合待查专业的所有学生记录
返回值:无
功 能:实现按专业查找学生记录。具体实现思路与Check_Name()基本一致。
(32)void Check_Origin(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查生源地
输 出:符合待查生源地的所有学生记录
返回值:无
功 能:实现按生源地查找学生记录。具体实现思路与Check_Name()基本一致。
(33)void Check_Ethnic(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查民族
输 出:符合待查民族的所有学生记录
返回值:无
功 能:实现按民族查找学生记录。具体实现思路与Check_Name()基本一致。
(34)void Check_Politic(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查政治面貌
输 出:符合待查政治面貌的所有学生记录
返回值:无
功 能:实现按政治面貌查找学生记录。具体实现思路与Check_Name()基本一致。
(35)void Check_Sex(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查性别
输 出:符合待查性别的所有学生记录
返回值:无
功 能:实现按性别查找学生记录。具体实现思路与Check_Name()基本一致。
(36)void Check_Income(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查家庭收入最低值minincome,待查家庭收入最高值maxincome
输 出:符合家庭收入范围的所有学生记录
返回值:无
功 能:实现按家庭收入范围查找学生记录。保存所有学生记录的结构体data,指示上级菜单的menuflag作为形参输入。声明整形变量flag指示是否找到范围内的学生记录,初始值置0。输入待查家庭收入最低值minincome,若输入-1,返回上级菜单,若输入超出合法范围,递归重新获得家庭收入范围。若输入合法,继续输入待查家庭收入最高值maxincome,若输入-1,返回上级菜单,若输入超出合法值,递归重新获得家庭收入范围,若maxincome小于minincome,递归重新获得家庭收入范围。minincome和maxincome输入均合法,遍历data,若找到符合输入家庭收入范围的学生记录,调用Show_Student()展示学生记录,flag置1。若flag最终为0,提示未查找到记录,结束。
(37)void Check_Chinese(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查语文成绩最低值minchinese,待查语文成绩最高值maxchinese
输 出:符合语文成绩范围的所有学生记录
返回值:无
功 能:实现按语文成绩范围查找学生记录。具体实现思路与Check_Income()基本一致。
(38)void Check_Math(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查数学成绩最低值minmath,待查数学成绩最高值maxmath
输 出:符合数学成绩范围的所有学生记录
返回值:无
功 能:实现按数学成绩范围查找学生记录。具体实现思路与Check_Income()基本一致。
(39)void Check_English(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查英语成绩最低值minenglish,待查英语成绩最高值maxenglish
输 出:符合英语成绩范围的所有学生记录
返回值:无
功 能:实现按英语成绩范围查找学生记录。具体实现思路与Check_Income()基本一致。
(40)void Check_Compre(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查综合成绩最低值mincompre,待查综合成绩最高值maxcompre
输 出:符合综合成绩范围的所有学生记录
返回值:无
功 能:实现按综合成绩范围查找学生记录。具体实现思路与Check_Income()基本一致。
(41)void Check_Score(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查入学总成绩最低值minscore,待查入学总成绩最高值maxscore
输 出:符合入学总成绩范围的所有学生记录
返回值:无
功 能:实现按入学总成绩范围查找学生记录。具体实现思路与Check_Income()基本一致,其中入学总成绩通过score[0]+ score[1]+ score[2]+ score[3]获得。
(42)void Count_Class_Score(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查班级
输 出:按输入班级,统计各个学生的入学总成绩,班级各科最高分、最低分,班级入学平均成绩
返回值:无
功 能:实现按输入班级,统计各个学生的入学总成绩,班级各科最高分、最低分,班级入学平均成绩。保存所有学生记录的结构体data,指示上级菜单的menuflag作为形参输入。要实现此功能,需要先对data的学生记录按照学号进行排序。声明以下整形变量:classflag指示待查班号是否找到,初始值置0;classsize指示班级人数。声明各科目最高值与最低值的初始整形变量,最低值置满分,最高值置0分。声明双精度浮点型变量classavg指示班级入学平均成绩。输入待查班级,若输入-1,返回上级菜单。若输入不为-1,遍历data,每当找到学生记录符合待查班级,classflag置1,classsize自增,将此学生记录中语文、数学、英语、综合成绩一同累加置classavg,并依次比较各科成绩最高值与最低值,即时更新。遍历结束,classavg=classacg/classsize得到班级入学总成绩平均值。若classflag为1,展示各科最高分、最低分、班级平均成绩,否则提示班级未找到,递归重新获得待查班级
(43)void Count_Grade_Major(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查年级
输 出:待查年级统计各专业的人数
返回值:无
功 能:实现按年级统计各专业的人数。保存所有学生记录的结构体data,指示上级菜单的menuflag作为形参输入。要实现此功能,需要先对data的数据按照专业排序。声明整形变量gradeflag指示待查年级是否找到。声明字符串tmp记录已查询完毕的专业。遍历data,若学生记录符合待查年纪,且学生专业非已查询完毕的专业,此位置记为i,gradeflag置1。由i向后遍历,若查找到专业与i位置的专业不同,此位置记为j。由于已经按照专业进行排序,故专业是连续排列的,i指示某专业中符合待查年级的第一个位置,j指示此专业末尾位置的下一个位置。在i~j之间计数,若学生记录符合待查年级,计数器自增。若最终gradeflag为0,提示未找到,递归重新获得待查年级。
(44)void Count_Class_Origin(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查班级
输 出:待查班级统计各个省市人数
返回值:无
功 能:实现按班级统计各个省市人数。实现具体思路与Count_Grade_Major()基本一致。
(45)void Count_Grade_Ethnic(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查年级
输 出:待查年级各个少数民族的人数
返回值:无
功 能:实现按年级统计各个少数民族人数。实现具体思路与Count_Grade_Major()基本一致。
(46)void Count_Major_Sex(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查专业
输 出:待查专业各个年级男女人数
返回值:无
功 能:实现按专业统计年级男女分布。保存所有学生记录的结构体data,指示上级菜单的menuflag作为形参输入。输入待查性别,若输入-1,返回上级菜单。遍历data,若学生记录的年级与上一个学生记录的年级不同,由此向后遍历,若找到男生,则男生计数器自增,若找到女生,则女生计数器自增。若学生记录与正查询年级不同,跳出循环,输入本年级男女人数,男女计数器归0。
(47)void Count_Grade_ClassPoor(Student data[],int menuflag)
输 入:保存所有学生记录的结构体data,指示上级菜单的menuflag,待查年级
输 出:待查年级所有班级中家庭收入低于班级平均的学生人数
返回值:无
功 能:实现按年级统计所有班级中家庭收入低于班级平均的学生人数。实现具体思路与Count_Grade_Major()基本一致。
(48)void Login(Student data[],int count)
输 入:剩余试错次数count,身份码
输 出:无
返回值:无
功 能:实现验证身份码登陆。利用getch()函数实现不回显录入字符,每当输入字符则打印“*”,实现密文输入。对于回退,设置判断条件,当输入回退是,打印“/b /b”,同时指示字符串位置的变量自减,实现密文回退。从外部文件读取管理员身份码和普通用户身份码,若比对成功,则进行对应跳转,否则剩余试错次数-1,递归。当剩余试错次数为0时,退出程序。
(49)void Change_Code(Student data[])
输 入:新身份码
输 出:无
返回值:无
功 能:实现身份码的更改。若管理员身份码与普通用户身份码重用,提示错误,递归重新获得新身份码。若管理员身份码或普通用户身份码超过限制长度,提示错误,递归重新获得新身份码。
(50)void Menu_Admin(Student stu[])
输 入:菜单选项
输 出:对应子菜单
返回值:无
功 能:展示管理员主菜单并提供子菜单选择。
(51)void Menu_User(Student stu[])
输 入:菜单选项
输 出:对应子菜单
返回值:无
功 能:展示普通用户主菜单并提供子菜单选择。
(52)void Menu_Change(Student stu[])
输 入:菜单选项
输 出:对应子菜单
返回值:无
功 能:展示删除/更改学生记录子菜单并提供菜单选择。
(53)void Menu_Check(Student stu[])
输 入:菜单选项
输 出:对应功能
返回值:无
功 能:展示查询功能自菜单并提供子菜单选择。
(54)void Menu_Count(Student stu[])
输 入:菜单选项
输 出:对应功能
返回值:无
功 能:展示统计功能子菜单并提供子菜单选择。
五、程序测试
图1 管理员登陆
图2 普通用户登陆
图3 登陆失败
图4 成功打开文件
图5 管理员主菜单
图6 普通用户主菜单
图7 管理员主菜单边界
图8 新建学生边界
图9 删除/更改学生档案
图10 更改名字
图11 更改名字成功
图12 查询与显示
图13 查询边界
图14 统计与显示
图15 按班级统计分数情况
图16 按年级统计专业人数
图17 按班级统计省市人数
图18 按年级统计少数民族人数
图19 按年级统计家庭收入低于平均人数
图20 更改身份码过长
图21 更改身份码重用
图22 结束字符画
六、设计小结
本任务设计的代码完成基本功能,但是有几个缺点:
1. 读入文件路径设置画蛇添足
在读入文件路径时,我将打开文件的指针设置为了只读方式打开文件,没有考虑新建空数据源的情况。我将代码修改为以附加的方式打开只写文件,实现了若文件不存在则新建文件的功能。
2. 从学号中提取班级的算法有缺陷
由于在数据结构中学生记录的学号字段我采用了整形变量存储,故学生的年级,班级我都是通过数学方法从学号中提取:
int num=20174314; int grade=num/10000; //grade=2017 int classnum=num/100-200000 //classnum=17
但是若学号为1999开头的,即学生记录拓展到90年代入学的学生,则我的代码不具有适用性,因此,我将代码修改如下:
int num=20174314; int classnum=)num/100)%10000 //classnum=17
这样从学号中提取班级的代码就具有了通用性。但是,最好的解决方案是将数据结构体进行修改,学号字段用字符串储存,在提取年级,班级时提取字串即可稳定解决。但相对应的,其边界判断将变得复杂。两种方式各有利弊,但是利用字符串进行存储相对更能保证运行的稳定,这是程序实现的最终目的,贪图简单轻松则可能出错。
七、使用说明
本程序提交的是cpp源代码,所以用DEV-CPP打开直接编译运行,然后按照程序提示操作即可。
八、附录
程序源代码参见C语言程序文件main.cpp。
#include "stdio.h" #include "string.h" #include "stdlib.h" #include "conio.h" //作者:20174314-王方正 //题目:《程序设计实践教程》教材22题 //完成时间:2019年9月11日 //指导老师:徐小青老师、李晓东老师 struct Student { int num;//学号 char name[10];//姓名 char major[20];//专业 char origin[8];//生源地 char ethnic[12];//民族 char sex[3];//性别 char politic[12];//政治面貌 double income;//家庭收入 double score[4];//学生成绩 }; void Menu_Admin(Student stu[]);//管理员账号主菜单 void Menu_User(Student stu[]);//用户账号主菜单 void Menu_Change(Student data,Student stu[],int check);//删除/修改学生档案子菜单 void Menu_Check(Student stu[],int menuflag);//查询与显示子菜单 void Menu_Count(Student stu[],int menuflag);//统计与显示子菜单 void Print_Welcome() { printf("\t\t\t\t _______ _ _______ _______ _______ _______ \n"); printf("\t\t\t\t|\\ /|( ____ \\( \\ ( ____ \\( ___ )( )( ____ \\\n"); printf("\t\t\t\t| ) ( || ( \\/| ( | ( \\/| ( ) || () () || ( \\/\n"); printf("\t\t\t\t| | _ | || (__ | | | | | | | || || || || (__ \n"); printf("\t\t\t\t| |( )| || __) | | | | | | | || |(_)| || __) \n"); printf("\t\t\t\t| || || || ( | | | | | | | || | | || ( \n"); printf("\t\t\t\t| () () || (____/\\| (____/\\| (____/\\| (___) || ) ( || (____/\\\n"); printf("\t\t\t\t(_______)(_______/(_______/(_______/(_______)|/ \\|(_______/\n\n"); } void Print_End()//结束程序彩蛋 { system("color fc"); printf("\t\t\t\t _______ _______ _______ ______ ______ _______ \n"); printf("\t\t\t\t( ____ \\( ___ )( ___ )( __ \\ ( ___ \\ |\\ /|( ____ \\\n"); printf("\t\t\t\t| ( \\/| ( ) || ( ) || ( \\ )| ( ) )( \\ / )| ( \\/\n"); printf("\t\t\t\t| | | | | || | | || | ) || (__/ / \\ (_) / | (__ \n"); printf("\t\t\t\t| | ____ | | | || | | || | | || __ ( \\ / | __) \n"); printf("\t\t\t\t| | \\_ )| | | || | | || | ) || ( \\ \\ ) ( | ( \n"); printf("\t\t\t\t| (___) || (___) || (___) || (__/ )| )___) ) | | | (____/\\\n"); printf("\t\t\t\t(_______)(_______)(_______)(______/ |/ \\___/ \\_/ (_______/\n"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 感谢使用!! │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); } int Length_Student(Student data[])//结构体长度 { int i;//循环用变量 for(i=0;data[i].num!=0;i++); return i; } void Load_Student(Student data[],FILE *fp)//从文件读取学生信息 { for(int i=0;!feof(fp);i++)//在文件到底之前,将文件中所有记录依次读入 { fscanf(fp,"%d",&data[i].num); fscanf(fp,"%s",data[i].name); fscanf(fp,"%s",data[i].major); fscanf(fp,"%s",data[i].origin); fscanf(fp,"%s",data[i].ethnic); fscanf(fp,"%s",data[i].sex); fscanf(fp,"%s",data[i].politic); fscanf(fp,"%lf",&data[i].income); fscanf(fp,"%lf",&data[i].score[0]); fscanf(fp,"%lf",&data[i].score[1]); fscanf(fp,"%lf",&data[i].score[2]); fscanf(fp,"%lf",&data[i].score[3]); } fclose(fp);//关闭文件 } void Overwrite_Student(Student data[],FILE *fp)//覆盖文件中的记录 { for(int i=0;i2020)//超出学生年级范围 { printf("\t\t\t\t学号输入错误!\n"); Get_Number(data,stu);//递归 return;//函数此处结束 } for(int i=0;i<=length;i++)//在原学号库中查重 { if(stu[i].num==tmp)//输入学号重复 { printf("\t\t\t\t学号输入重复!\n"); Get_Number(data,stu);//递归 return;//函数此处结束 } } } data->num=tmp;//最终将合法值或-1传入临时结构体 return; } void Get_Name(Student *data) { printf("\t\t\t\t请输入姓名(中文名,输入-1返回上级菜单):"); char tmp[10];//临时变量,保存输入值 scanf("%s",tmp); int length=strlen(tmp);//获取字符串长度 if(strcmp(tmp,"-1")!=0)//输入-1,返回上级菜单 { for(int i=0;i<=length;i++) { if(tmp[i]>=1&&tmp[i]<=127)//如果输入了非中文字符,判断为输入错误 { printf("\t\t\t\t姓名输入错误!\n"); Get_Name(data); return; } } } strcpy(data->name,tmp);//将合法值传入临时结构体 return; } void Get_Major(Student *data) { printf("\t\t\t\t请输入专业\n\t\t\t\t(信息与计算科学/信息安全/计算机科学与技术/信息管理与信息系统/电子信息工程/通信工程/行政管理/保密管理,输入-1返回上级菜单):"); int flag=0;//指示专业是否存在 char tmp[20];//临时变量,保存输入值 char majorlist[8][20]={"信息与计算科学","信息安全","计算机科学与技术","信息管理与信息系统","电子信息工程", "通信工程","行政管理","保密管理"};//比对专业信息的库 scanf("%s",tmp); if(strcmp(tmp,"-1")!=0)//输入-1,返回上级菜单 { for(int i=0;i<8;i++) if(strcmp(tmp,majorlist[i])==0) { flag=1; break; } if(flag==0)//没有找到库中的专业 { printf("\t\t\t\t专业输入错误!\n"); Get_Major(data);//递归 return; } } strcpy(data->major,tmp); return; } void Get_Origin(Student *data) { printf("\t\t\t\t请输入生源地(省份名称,输入-1返回上级菜单):"); int flag; char tmp[8]; char originlist[34][8]={"北京","天津","上海","重庆","河北","山西","辽宁","吉林","黑龙江", "江苏","浙江","安徽","福建","江西","山东","河南","湖北","湖南","广东","海南","四川","贵州", "云南","陕西","甘肃","青海","台湾","内蒙古","广西","西藏","宁夏","新疆","香港","澳门"}; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { for(int i=0;i<34;i++) if(strcmp(tmp,originlist[i])==0) { flag=1; break; } if(flag==0)//没有找到库中的省份 { printf("\t\t\t\t生源地输入错误!\n"); Get_Origin(data);//递归 return; } } strcpy(data->origin,tmp); return; } void Get_Sex(Student *data) { printf("\t\t\t\t请输入性别(男/女,输入-1返回上级菜单):"); char male[3]="男",female[3]="女",tmp[3]; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { if(strcmp(tmp,male)*strcmp(tmp,female)!=0)//如果输入的性别不是男或女中的任一个,输入错误 { printf("\t\t\t\t性别输入错误!\n"); Get_Sex(data); return; } } strcpy(data->sex,tmp); return; } void Get_Ethnic(Student *data) { printf("\t\t\t\t请输入民族(民族名称,输入-1返回上级菜单):"); int flag=0; char tmp[12]; char ethniclist[56][12]={"汉族","蒙古族","回族","藏族","维吾尔族","苗族","彝族","壮族", "布依族","朝鲜族","满族","侗族","瑶族","白族","土家族","哈尼族","哈萨克族","傣族","黎族", "僳僳族","佤族","畲族","高山族","拉祜族","水族","东乡族","纳西族","景颇族","柯尔克孜族", "土族","达斡尔族","仫佬族","羌族","布朗族","撒拉族","毛南族","仡佬族","锡伯族","阿昌族", "普米族","塔吉克族","怒族","乌孜别克族","俄罗斯族","鄂温克族","德昂族","保安族","裕固族", "京族","塔塔尔族","独龙族", "鄂伦春族","赫哲族","门巴族","珞巴族","基诺族"}; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { for(int i=0;i<57;i++) if(strcmp(tmp,ethniclist[i])==0){ flag=1; break; } if(flag==0) { printf("\t\t\t\t民族输入错误!\n"); Get_Ethnic(data);//递归 return; } } strcpy(data->ethnic,tmp); return; } void Get_Politic(Student *data) { printf("\t\t\t\t请输入政治面貌\n\t\t\t\t(群众/无党派人士/共青团员/入党积极分子/中共预备党员/中共党员,输入-1返回上级菜单):"); int flag=0; char tmp[20]; char politiclist[6][20]={"群众","无党派人士","共青团员","入党积极分子","中共预备党员","中共党员"}; scanf("%s",tmp); if(strcmp(tmp,"-1")!=0) { for(int i=0;i<8;i++) if(strcmp(tmp,politiclist[i])==0) { flag=1; break; } if(flag==0) { printf("\t\t\t\t政治面貌输入错误!\n"); Get_Politic(data);//递归 return; } } strcpy(data->politic,tmp); return; } void Get_Income(Student *data) { printf("\t\t\t\t请输入家庭收入(0~99999,输入-1返回上级菜单):"); double tmp=-2;//初始值非法值,防止输入字符产生错误 fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>=100000)//输入的家庭收入超出范围 { printf("\t\t\t\t家庭收入输入错误!\n"); Get_Income(data); return; } } data->income=tmp; } void Get_Chinese(Student *data) { printf("\t\t\t\t请输入语文成绩(0~150,输入-1返回上级菜单):"); double tmp=-2;//初始置非法值 fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>150) { printf("\t\t\t\t语文成绩输入错误!\n"); Get_Chinese(data); return; } } data->score[0]=tmp; } void Get_Math(Student *data) { printf("\t\t\t\t请输入数学成绩(0~150,输入-1返回上级菜单):"); double tmp=-2; fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>150){ printf("\t\t\t\t数学成绩输入错误!\n"); Get_Math(data); return; } } data->score[1]=tmp; } void Get_English(Student *data) { printf("\t\t\t\t请输入英语成绩(0~150,输入-1返回上级菜单):"); double tmp=-2; fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>150){ printf("\t\t\t\t英语成绩输入错误!\n"); Get_English(data); return; } } data->score[2]=tmp; } void Get_Compre(Student *data) { printf("\t\t\t\t请输入综合成绩(0~300,输入-1返回上级菜单):"); double tmp=-2; fflush(stdin); scanf("%lf",&tmp); if(tmp!=-1) { if(tmp<0||tmp>300) { printf("\t\t\t\t综合成绩输入错误!\n"); Get_Compre(data); return; } } data->score[3]=tmp; } void New_Student(Student *data,FILE *fp,Student stu[])//添加新的学生记录 { int length=Length_Student(stu);//计算内存结构体记录个数 system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 新建学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Get_Number(data,stu);//获得学号,函数将临时结构体data中的num字段改为-1或合法值 if(data->num==-1) Menu_Admin(stu);//若临时结构体data中的num字段为-1,调用函数返回上级菜单 //若临时结构体data中的num字段为合法值,进入程序继续获得下一个字段的值 Get_Name(data); if(strcmp(data->name,"-1")==0) Menu_Admin(stu); Get_Major(data); if(strcmp(data->major,"-1")==0) Menu_Admin(stu); Get_Sex(data); if(strcmp(data->sex,"-1")==0) Menu_Admin(stu); Get_Origin(data); if(strcmp(data->origin,"-1")==0) Menu_Admin(stu); Get_Ethnic(data); if(strcmp(data->ethnic,"-1")==0) Menu_Admin(stu); Get_Politic(data); if(strcmp(data->politic,"-1")==0) Menu_Admin(stu); Get_Income(data); if(data->income==-1) Menu_Admin(stu); Get_Chinese(data); if(data->score[0]==-1) Menu_Admin(stu); Get_Math(data); if(data->score[1]==-1) Menu_Admin(stu); Get_English(data); if(data->score[2]==-1) Menu_Admin(stu); Get_Compre(data); if(data->score[3]==-1) Menu_Admin(stu); strcpy(stu[length+1].major,stu[length].major);//将之前存放的文件名置入结构体末的下一个位置 stu[Length_Student(stu)]=*data;//将新的记录从临时结构体data中置入原结构体stu末 printf("\t\t\t\t是否继续录入?(Y/N)"); char key; getchar();//从键盘读取字符,保证key正常录入 scanf("%c",&key); if(key=='Y') New_Student(data,fp,stu);//递归 else Menu_Admin(stu);//返回上级菜单 } void Delete_Student(Student data[],int i)//删除学生档案记录 { printf("\n\t\t\t\t确认删除?(Y/N)"); char ch; Student tmp;//临时结构体,传入更改学生档案函数,用于临时记录修改值 getchar();//清空字符缓冲区 scanf("%c",&ch); if(ch=='Y') { for(int j=i;j =rear) { return; } int i=front; int j=rear; Student tmp=data[front];//轴 while(i =data[i].num)//找比轴大的记录 { i++; } data[j]=data[i];//放到轴后面 } data[i]=tmp;//轴置入中间 Sort_Number(data,front,i-1);//轴的前一半,递归 Sort_Number(data,i+1,rear);//轴的后一半,递归 } void Sort_Origin(Student data[],int front,int rear)//对全部学生信息按生源地快速排序 { if(front>=rear) { return; } int i=front; int j=rear; Student tmp=data[front]; while(i =0) { i++; } data[j]=data[i]; } data[i]=tmp; Sort_Origin(data,front,i-1); Sort_Origin(data,i+1,rear); } void Sort_Ethnic(Student data[],int front,int rear)//对全部学生信息按民族快速排序 { if(front>=rear) { return; } int i=front; int j=rear; Student tmp=data[front]; while(i =0) { i++; } data[j]=data[i]; } data[i]=tmp; Sort_Ethnic(data,front,i-1); Sort_Ethnic(data,i+1,rear); } void Sort_Major(Student data[],int front,int rear)//对全部学生信息按民族快速排序 { if(front>=rear) { return; } int i=front; int j=rear; char key[8]; Student tmp=data[front]; while(i =0) { i++; } data[j]=data[i]; } data[i]=tmp; Sort_Major(data,front,i-1); Sort_Major(data,i+1,rear); } int Check_Number(Student data[],int menuflag)//按学号查询学生,二分查找 { int length=Length_Student(data)-1;//获得内存结构体记录个数 int front=0;//起始位置 int rear=length;//末尾位置 int mid;//中间点 int flag=0;//指示查找是否成功 int tmp; printf("\t\t\t\t请输入待查询学号(八位学号,输入-1返回上级菜单):"); fflush(stdin); scanf("%d",&tmp); if(tmp==-1) return -1;//若输入-1,返回值为-1,返回上级菜单 while(front<=rear) { mid=(front+rear)/2;//二分 if(tmpdata[mid].num)//目标在后一半 front=mid+1;//起始置为二分后一个位置 else if(tmp==data[mid].num)//找到目标值 { flag=1;//指示找到目标值 return mid;//若查找成功,返回值为目标位置 } } if(flag==0)//未找到目标值 { printf("\t\t\t\t非法输入或学号不存在!\n"); int check=Check_Number(data,menuflag);//递归,将内层的返回值传出外层函数 return check;//返回值为目标位置 } } void Check_Name(Student data[],int menuflag)//按专业查询学生,menuflag指示上级菜单 { int length=Length_Student(data)-1;//获得记录个数 int flag=0; char tmp[10]; printf("\t\t\t\t请输入待查询姓名(中文名,输入-1返回上级菜单):"); scanf("%s",tmp); if(strcmp(tmp,"-1")==0&&menuflag==1) Menu_Check(data,menuflag);//menuflag为1,返回查询与显示的子菜单 if(strcmp(tmp,"-1")==0&&menuflag==0) Menu_Admin(data);//menuflag为0,返回管理员主菜单 for(int i=0;i<=length;i++) { if(strcmp(data[i].name,tmp)==0)//找到目标记录 { flag=1;//指示找到目标记录 Show_Student(data,i);//展示目标记录详细信息 } } if(flag==0)//未找到目标记录 { printf("\t\t\t\t非法输入或姓名不存在!\n"); Check_Name(data,menuflag);//递归 } return; } void Check_Grade(Student data[],int menuflag)//按年级查询学生 { int length=Length_Student(data)-1; int flag=0; int tmp; printf("\t\t\t\t请输入待查询年级(四位年级,输入-1返回上级菜单):"); fflush(stdin); scanf("%d",&tmp); if(tmp==-1) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if(data[i].num/10000==tmp) { Show_Student(data,i); flag=1; if(data[i].num/10000!=data[i+1].num/10000) break; //按照学号顺序排序,下一个位置的年级与此位置年级不同时,同一个年级的记录已经全部展示 } } if(flag==0) { printf("\t\t\t\t非法输入或年级不存在!\n"); Check_Grade(data,menuflag); } } void Check_Class(Student data[],int menuflag)//按班级查询学生 { int length=Length_Student(data)-1; int flag=0; int tmp; printf("\t\t\t\t请输入待查询班级(四位班号,输入-1返回上级菜单):"); fflush(stdin); scanf("%d",&tmp); if(tmp==-1) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if((data[i].num/100)%10000==tmp) { Show_Student(data,i); flag=1; if((data[i].num/100)%10000!=(data[i+1].num/100)%10000) break; } } if(flag==0) { printf("\t\t\t\t非法输入或班级不存在!\n"); Check_Class(data,menuflag); } } void Check_Major(Student data[],int menuflag)//按专业查询学生 { int length=Length_Student(data)-1; int flag=0; char tmp[20]; printf("\t\t\t\t请输入待查询专业\n\t\t\t\t(信息与计算科学/信息安全/计算机科学与技术/信息管理与信息系统/电子信息工程/通信工程/行政管理/保密管理,输入-1返回上级菜单):"); scanf("%s",tmp); if(strcmp(tmp,"-1")==0) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if(strcmp(data[i].major,tmp)==0) { flag=1; Show_Student(data,i); } } if(flag==0) { printf("\t\t\t\t非法输入或专业不存在!\n"); Check_Major(data,menuflag); } } void Check_Origin(Student data[],int menuflag)//按生源地查询学生 { int length=Length_Student(data)-1; int flag=0; char origin[20]; printf("\t\t\t\t请输入待查询生源地(省份名称,输入-1返回上级菜单):"); scanf("%s",origin); if(strcmp(origin,"-1")==0) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if(strcmp(data[i].origin,origin)==0) { flag=1; Show_Student(data,i); } } if(flag==0){ printf("\t\t\t\t非法输入或生源地不存在!\n"); Check_Origin(data,menuflag); } } void Check_Ethnic(Student data[],int menuflag)//按民族查询学生 { int length=Length_Student(data)-1; int flag=0; char ethnic[20]; printf("\t\t\t\t请输入待查询民族(民族名称,输入-1返回上级菜单):"); scanf("%s",ethnic); if(strcmp(ethnic,"-1")==0) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if(strcmp(data[i].ethnic,ethnic)==0) { flag=1; Show_Student(data,i); } } if(flag==0) { printf("\t\t\t\t非法输入或民族不存在!\n"); Check_Ethnic(data,menuflag); } } void Check_Politic(Student data[],int menuflag)//按政治面貌查询学生 { int length=Length_Student(data)-1; int flag=0; char politic[20]; printf("\t\t\t\t请输入政治面貌\n\t\t\t\t(群众/无党派人士/共青团员/入党积极分子/中共预备党员/中共党员,输入-1返回上级菜单):"); scanf("%s",politic); if(strcmp(politic,"-1")==0) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if(strcmp(data[i].politic,politic)==0) { flag=1; Show_Student(data,i); } } if(flag==0) { printf("\t\t\t\t非法输入!\n"); Check_Politic(data,menuflag); } } void Check_Sex(Student data[],int menuflag)//按性别查询学生 { int length=Length_Student(data)-1; int flag=0; char sex[20]; printf("\t\t\t\t请输入待查询性别(男/女,输入-1返回上级菜单):"); scanf("%s",sex); if(strcmp(sex,"-1")==0) Menu_Check(data,menuflag); for(int i=0;i<=length;i++) { if(strcmp(data[i].sex,sex)==0) { flag=1; Show_Student(data,i); } } if(flag==0) { printf("\t\t\t\t非法输入!\n"); Check_Sex(data,menuflag); } } void Check_Income(Student data[],int menuflag)//按家庭收入查询学生 { int length=Length_Student(data)-1; int flag=0;//指示是否找到记录 int minincome=-2,maxincome=100000; fflush(stdin); printf("\t\t\t\t请输入待查询家庭收入最低值:"); scanf("%d",&minincome);//输入家庭收入最低值 if(minincome==-1) { Menu_Check(data,menuflag);//输入-1返回上级菜单 return; } else if(minincome<0||minincome>99999)//输入越界 { printf("\t\t\t\t非法输入!\n"); Check_Income(data,menuflag);//递归 return; } fflush(stdin); printf("\t\t\t\t请输入待查询家庭收入最高值:"); scanf("%d",&maxincome);//输入家庭收入最高值 if(maxincome==-1) { Menu_Check(data,menuflag);//输入-1返回上级菜单 return; } else if(maxincome 99999) //家庭收入最高值<家庭收入最低值,汇报错误 //输入越界也报错 { printf("\t\t\t\t非法输入!\n"); Check_Income(data,menuflag);//递归 return; } for(int i=0;i<=length;i++)//输入正确,查找家庭收入在范围内的记录 if(data[i].income<=maxincome&&data[i].income>=minincome) { Show_Student(data,i); flag=1; } if(flag==0) printf("\t\t\t\t未找到记录!\n"); } void Check_Chinese(Student data[],int menuflag)//按语文成绩查询学生 { int length=Length_Student(data)-1; int flag=0; int minchinese=-2,maxchinese=151; char major[20]; fflush(stdin); printf("\t\t\t\t请输入待查询语文成绩最低值:"); scanf("%d",&minchinese); if(minchinese==-1) { Menu_Check(data,menuflag); return; } else if(minchinese<0||minchinese>150)//输入越界 { printf("\t\t\t\t非法输入!\n"); Check_Chinese(data,menuflag);//递归 return; } fflush(stdin); printf("\t\t\t\t请输入待查询语文成绩最高值:"); scanf("%d",&maxchinese); if(maxchinese==-1) { Menu_Check(data,menuflag); return; } else if(maxchinese 150) { printf("\t\t\t\t非法输入!\n"); Check_Chinese(data,menuflag); return; } for(int i=0;i<=length;i++) if(data[i].score[0]<=maxchinese&&data[i].score[0]>=minchinese) { Show_Student(data,i); flag=1; } if(flag==0) printf("\t\t\t\t未找到记录!\n"); } void Check_Math(Student data[],int menuflag)//按数学成绩查询学生 { int length=Length_Student(data)-1; int flag=0; int minmath=-2,maxmath=151; char major[20]; fflush(stdin); printf("\t\t\t\t请输入待查询数学成绩最低值:"); scanf("%d",&minmath); if(minmath==-1) { Menu_Check(data,menuflag); return; } else if(minmath<0||minmath>150) { printf("\t\t\t\t非法输入!\n"); Check_Chinese(data,menuflag); return; } fflush(stdin); printf("\t\t\t\t请输入待查询数学成绩最高值:"); scanf("%d",&maxmath); if(maxmath==-1) { Menu_Check(data,menuflag); return; } else if(maxmath 150) { printf("\t\t\t\t非法输入!\n"); Check_Math(data,menuflag); return; } for(int i=0;i<=length;i++) if(data[i].score[1]<=maxmath&&data[i].score[1]>=minmath) { Show_Student(data,i); flag=0; } if(flag==0) printf("\t\t\t\t未找到记录!\n"); } void Check_English(Student data[],int menuflag)//按英语成绩查询学生 { int length=Length_Student(data)-1; int flag=0; int minenglish=-2,maxenglish=151; char major[20]; fflush(stdin); printf("\t\t\t\t请输入待查询英语成绩最低值:"); scanf("%d",&minenglish); if(minenglish==-1) { Menu_Check(data,menuflag); return; } else if(minenglish<0||minenglish>150) { printf("\t\t\t\t非法输入!\n"); Check_English(data,menuflag); return; } fflush(stdin); printf("\t\t\t\t请输入待查询英语成绩最高值:"); scanf("%d",&maxenglish); if(maxenglish==-1) { Menu_Check(data,menuflag); return; } else if(maxenglish 150) { printf("\t\t\t\t非法输入!\n"); Check_English(data,menuflag); return; } for(int i=0;i<=length;i++) if(data[i].score[2]<=maxenglish&&data[i].score[2]>=minenglish) { Show_Student(data,i); flag=1; } if(flag==0) printf("\t\t\t\t未找到记录!\n\t\t\t\t"); } void Check_Compre(Student data[],int menuflag)//按综合成绩查询学生 { int length=Length_Student(data)-1; Sort_Number(data,0,length); int flag=0; int mincompre=-2,maxcompre=301; char major[20]; fflush(stdin); printf("\t\t\t\t请输入待查询综合成绩最低值:"); scanf("%d",&mincompre); if(mincompre==-1) { Menu_Check(data,menuflag); return; } else if(mincompre<0||mincompre>150) { printf("\t\t\t\t非法输入!\n"); Check_Compre(data,menuflag); return; } fflush(stdin); printf("\t\t\t\t请输入待查询综合成绩最高值:"); scanf("%d",&maxcompre); if(maxcompre==-1) { Menu_Check(data,menuflag); return; } else if(maxcompre 750) { printf("\t\t\t\t非法输入!\n"); Check_Compre(data,menuflag); return; } for(int i=0;i<=length;i++) if(data[i].score[3]<=maxcompre&&data[i].score[3]>=mincompre) { Show_Student(data,i); flag=1; } if(flag==0) printf("\t\t\t\t未找到记录!\n\t\t\t\t"); } void Check_Score(Student data[],int menuflag)//按入学总成绩查询学生 { int length=Length_Student(data)-1; Sort_Number(data,0,length); int flag=0; int minscore=-2,maxscore=751; char major[20]; fflush(stdin); printf("\t\t\t\t请输入待查询总入学成绩最低值:"); scanf("%d",&minscore); if(minscore==-1) { Menu_Check(data,menuflag); return; } else if(minscore<0||minscore>750) { printf("\t\t\t\t非法输入!\n"); Check_Score(data,menuflag); return; } fflush(stdin); printf("\t\t\t\t请输入待查询总入学成绩最高值:"); scanf("%d",&maxscore); if(maxscore==-1) { Menu_Check(data,menuflag); return; } if(maxscore 750) { printf("\t\t\t\t非法输入!\n"); Check_Score(data,menuflag); return; } for(int i=0;i<=length;i++) if(data[i].score[0]+data[i].score[1]+data[i].score[2]+data[i].score[3]<=maxscore&& data[i].score[0]+data[i].score[1]+data[i].score[2]+data[i].score[3]>=minscore) { Show_Student(data,i); flag=1; } if(flag==0) printf("\t\t\t\t未找到记录!\n\t\t\t\t"); } void Count_Class_Score(Student data[],int menuflag)//按班级,统计分数情况 { int MaxChinese=0,MaxMath=0,MaxEnglish=0,MaxCompre=0;//各个成绩最值初始化 int MinChinese=150,MinMath=150,MinEnglish=150,MinCompre=300; int classnum;//待查询的班号 int classflag=0;//指示班号是否找到 int classsize=0;//班级人数 int length=Length_Student(data);//统计记录总数 double classavg;//班级平均分 printf("\t\t\t\t请输入待查询班级(四位班号,输入-1返回上级菜单):"); fflush(stdin); scanf("%d",&classnum); if(classnum==-1) Menu_Count(data,menuflag);//输入-1返回上级菜单 for(int i=0;i<=length;i++) { if((data[i].num/100)%10000==classnum)//找到待查询班号 { printf("\t\t\t\t#学号:%d\t姓名:%s\t入学成绩:%.2lf\n",data[i].num,data[i].name,data[i].score[0]+data[i].score[1]+data[i].score[2]+data[i].score[3]); //展示班级学生入学总成绩 classflag=1;//指示待查询班级找到 classsize++;//统计班级人数 classavg=classavg+data[i].score[0]+data[i].score[1]+data[i].score[2]+data[i].score[3];//班级入学总成绩累加 if(data[i].score[0]>MaxChinese) MaxChinese=data[i].score[0];//比较查找各科最值 if(data[i].score[0] MaxMath) MaxMath=data[i].score[1]; if(data[i].score[1] MaxEnglish) MaxEnglish=data[i].score[2]; if(data[i].score[2] MaxCompre) MaxCompre=data[i].score[3]; if(data[i].score[3] 18) { printf("\t\t\t\t身份码过长!\n\t\t\t\t"); system("pause"); Change_Code(data); } printf("\t\t\t\t请输入新的管理员身份码(20位以内,输入-1返回上级菜单):"); scanf("%s",tmp[1]); if(strcmp(tmp[1],"-1")==0) Menu_Admin(data); else if(strlen(tmp[1])>18) //输入身份码过长 { printf("\t\t\t\t身份码过长!\n\t\t\t\t"); system("pause"); Change_Code(data); return; } else if(strcmp(tmp[0],tmp[1])==0) { printf("\n\t\t\t\t身份码重用!\n\t\t\t\t"); system("pause"); Change_Code(data); return; } fp=fopen("code.txt","w");//将新输入的身份码存入外存文件 fprintf(fp,"%s\n%s",tmp[0],tmp[1]); fclose(fp); printf("\n\t\t\t\t修改成功!\n\t\t\t\t"); system("pause"); Menu_Admin(data);//返回管理员主菜单 } void Menu_Admin(Student stu[]) { system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 学生档案管理系统(管理员版) │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #1.新建学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #2.删除/更改学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #3.查询与显示 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #4.统计与显示 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #5.更改身份码 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #0.保存并退出 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t#请键入功能编号:"); int n=-1;//初始置非法值 int check; fflush(stdin);//清空缓存区,防止输入字符导致循环 scanf("%d",&n); Student tmp; FILE *fp; switch(n) { case 0: fp=fopen(stu[Length_Student(stu)].major, "w");//从结构体中读取文件名 Overwrite_Student(stu,fp);//将内存结构体中的记录写入外存文件 fclose(fp); system("cls"); Print_End();//展示结束画面 exit(0); case 1: New_Student(&tmp,fp,stu);//调用创建新学生档案的子函数 system("pause"); Menu_Admin(stu);//创建新学生子函数结束,递归到管理员主菜单 break; case 2: if(Length_Student(stu)==0)//内存结构体中无记录,无法更改/删除 { printf("\t\t\t\t数据源为空!\n\t\t\t\t"); system("pause"); Menu_Admin(stu); break; } system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 删除/更改学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Number(stu,0,Length_Student(stu)-1); Check_Name(stu,0); check=Check_Number(stu,1); if(check==-1) Menu_Admin(stu); else Menu_Change(tmp,stu,check); break; case 3: if(Length_Student(stu)==0)//内存结构体中无记录,无法查询 { printf("\t\t\t\t数据源为空!\n\t\t\t\t"); system("pause"); Menu_Admin(stu); break; } Sort_Number(stu,0,Length_Student(stu)-1);//对学号进行快速排序 Menu_Check(stu,1);//指示从管理员主菜单调用,menuflag置1 break; case 4: if(Length_Student(stu)==0)//内存结构体中无记录,无法统计 { printf("\t\t\t\t数据源为空!\n\t\t\t\t"); system("pause"); Menu_Admin(stu); break; } Menu_Count(stu,1);//指示从管理员主菜单调用,menuflag置1 break; case 5: Change_Code(stu); default: printf("\t\t\t\t非法输入!\n\t\t\t\t"); system("pause"); Menu_Admin(stu); break; } } void Menu_User(Student stu[]) { system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 学生档案管理系统(用户版) │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #1.查询与显示 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #2.统计与显示 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #0.退出 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t#请键入功能编号:"); int n=-1; fflush(stdin);//清空缓存区,防止输入字符导致循环 scanf("%d",&n); switch(n) { case 0: system("cls"); Print_End(); exit(0); break; case 1: if(Length_Student(stu)==0)//内存结构体中无记录,无法查找 { printf("\t\t\t\t数据源为空!\n\t\t\t\t"); system("pause"); Menu_Admin(stu); break; } Sort_Number(stu,0,Length_Student(stu)); Menu_Check(stu,0);//指示从用户主菜单调用,menuflag置0 break; case 2: Menu_Count(stu,0);//指示从用户主菜单调用,menuflag置0 if(Length_Student(stu)==0)//内存结构体中无记录,无法查找 { printf("\t\t\t\t数据源为空!\n\t\t\t\t"); system("pause"); Menu_Admin(stu); break; } break; default: printf("\t\t\t\t非法输入!\n\t\t\t\t"); system("pause"); Menu_User(stu); break; } } void Menu_Change(Student data,Student stu[],int check) { system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 删除/更改学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Show_Student(stu,check); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #1.修改学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #2.删除学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #0.返回上级菜单 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t请键入功能编号:"); int n=-1; fflush(stdin); scanf("%d",&n); FILE *fp; switch(n) { case 0: Menu_Admin(stu); break; case 1: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 删除/更改学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Show_Student(stu,check);//展示待更改的学生记录 Change_Student(data,stu,check); Menu_Change(data,stu,check); break; case 2: Delete_Student(stu,check); break; default: printf("\t\t\t\t非法输入!\n"); system("pause"); Menu_Change(data,stu,check); break; } } void Menu_Check(Student stu[],int menuflag) { system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 查询与显示 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #1.按学号查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #2.按姓名查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #3.按班级查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #4.按年级查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #5.按专业查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #6.按生源地查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #7.按民族查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #8.按性别查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #9.按政治面貌查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #10.按家庭收入查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #11.按语文成绩查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #12.按数学成绩查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #13.按英语成绩查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #14.按综合成绩查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #15.按入学总成绩查询学生档案 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #0.返回上级菜单 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t请键入功能编号:"); int n=-1; int check; fflush(stdin); scanf("%d",&n); switch(n) { case 0: if(menuflag==1) Menu_Admin(stu);//menuflag为1,指示从管理员主菜单调用 if(menuflag==0) Menu_User(stu);//menuflag为0,指示从用户主菜单调用 break; case 1: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按学号查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); check=Check_Number(stu,menuflag); if(check==-1) Menu_Check(stu,menuflag); else { Show_Student(stu,check); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); } break; case 2: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按姓名查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Name(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 3: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按班级查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Class(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 4: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按年级查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Grade(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 5: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按专业查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Major(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 6: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按生源地查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Origin(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 7: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按民族查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Ethnic(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 8: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按性别查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Sex(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 9: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按政治面貌查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Politic(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 10: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按家庭收入查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Income(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 11: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按语文成绩查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Chinese(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 12: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按数学成绩查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Math(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 13: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按英语成绩查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_English(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 14: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按综合成绩查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Compre(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; case 15: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按总入学成绩查询学生档案 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Check_Score(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; default: printf("\t\t\t\t非法输入!\n\t\t\t\t"); system("pause"); Menu_Check(stu,menuflag); break; } } void Menu_Count(Student stu[],int menuflag) { system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 统计与显示 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #1.按班级统计分数情况 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #2.按年级统计专业人数 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #3.按班级统计省市人数 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #4.按年级统计少数民族人数 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #5.按专业统计男女人数 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #6.按年级统计家庭收入低于平均人数 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t│ #0.返回上级菜单 │\n"); printf("\t\t\t\t│ │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); printf("\t\t\t\t请键入功能编号:"); int n=-1; int length=Length_Student(stu)-1; fflush(stdin); scanf("%d",&n); switch(n) { case 0: if(menuflag==1) Menu_Admin(stu); if(menuflag==0) Menu_User(stu); break; case 1: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按班级统计分数情况 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Number(stu,0,length);//对学号进行快速排序 Count_Class_Score(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; case 2: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按年级统计专业人数 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Major(stu,0,length);//对专业进行快速排序 Count_Grade_Major(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; case 3: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按班级统计省市人数 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Origin(stu,0,length);//对生源地进行快速排序 Count_Class_Origin(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; case 4: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按年级统计少数民族人数 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Ethnic(stu,0,length);//对民族进行快速排序 Count_Grade_Ethnic(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; case 5: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按专业统计男女人数 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Number(stu,0,length); Count_Major_Sex(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; case 6: system("cls"); printf("\t\t\t\t╭-----------------------------------------------------------╮\n"); printf("\t\t\t\t│ 按年级统计家庭收入低于平均人数 │\n"); printf("\t\t\t\t╰-----------------------------------------------------------╯\n"); Sort_Number(stu,0,length); Count_Grade_ClassPoor(stu,menuflag); printf("\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; default: printf("\t\t\t\t非法输入!\n\t\t\t\t"); system("pause"); Menu_Count(stu,menuflag); break; } } int main() { Student stu[500]; Login(stu,5); return 0; }