文件管理系统开发案例----学生成绩管理系统的设计教学目的:了解文件管理系统的设计步骤。将课程的主要知识内容融会贯通于该案例中。变松散的知识点的学习为知识的灵活掌握与应用。分别从结构化层面和面向对象的层面了解抽象思维的设计思想。训练学生的综合设计和调试程序的能力。教学讲解重点:避免原有内容的重复讲解,突出强调难点和易错点的讲解,包括:•复杂数据结构的访问层次和语句结构•根据函数功能确定函数参数及返回值类型•单链表的操作函数中表头指针的变化•根据文件操作数据类型和文件的有无选取正确的文件打开方式和文件读写函数。通过代码的不同组织了解不同层次的抽象设计思想,包括函数库、接口、类等概念,进一步区分结构化程序设计过程和面向对象设计中函数的不同使用方式和意义通过代码组织理解文件包含的作用、掌握多文件操作的方法。引导学生思考如何对系统功能的进一步完善和对代码的进一步优化。学生成绩管理系统设计要求:学生信息以数据文件的形式存放在磁盘中,包括学号、姓名、班级、语文、数学、英语三门课程的成绩,系统对学生信息可以进行各种增、删、改、排序及对文件进行读写等功能。需求分析总体设计详细设计及编码代码组织---编程抽象一、需求分析能从文件中读入学生记录存于计算机中,同时也能将学生记录保存到磁盘文件;能按不同方式添加新学生记录;能对指定的学生记录进行修改、删除;能按照不同条件查询学生记录能对学生成绩进行统计并显示统计结果可对学生表按条件进行排序可用菜单形式显示系统功能供用户选择,并能从不同功能操作中返回到菜单成绩管理更新模块输入模块查询模块统计模块输出模块文件输入键盘输入按学号查询按姓名查询增加记录删除记录修改记录排序记录输出至文件屏幕显示统计各段人数系统功能模块图二、总体设计基本流程功能模块设计数据结构设计函数功能描述开始打开文件读文件并存入数组或链表调用菜单函数选择菜单操作退出系统吗调用相应函数完成相应操作已存盘否调用存盘函数结束否是否是1、基本流程输入模块:实现将数据输入数组或链表查询模块:在数组或链表中实现按不同字段进行查询更新模块:实现对记录的增、删、改、排序等操作统计模块:实现各种统计功能输出模块:实现将处理后的数据写入文件或在屏幕上输出的功能。2、功能模块设计学生成绩信息结构structstudent{charnum[8];charname[20];ints[3];//三门课成绩}若通过数组实现,则定义结构数组structstudentstu[N];N为已定义过的符号常量若通过单链表实现,则单链表结点结构定义:structnode{charnum[8];charname[20];ints[3];structnode*next;}3、数据结构设计voiddisplay(studentstu[],intlen)功能:显示长度为len的学生表中存储的学生记录。voidsearch(studentstu[],intlen)功能:在长度为len的学生表中按姓名或学号查找指定的学生记录。intappend(studentstu[],intlen)功能:在长度为len的学生表的末尾添加新的学生记录intdel(studentstu[],intlen)功能:从长度为len的学生表中删除指定学号的学生voidmodify(studentstu[],intlen)功能:修改长度为len的学生表中指定学号的学生记录4、函数功能描述(数据结构以结构数组为例)voidcount(studentstu[],intlen)功能:对长度为len的学生表按要求进行统计voidsort(studentstu[],intlen)功能:将长度为len的学生表中记录按要求排序voidsave(studentstu[],intlen)功能:将长度为len的学生表中记录保存到文件intreadfile(studentstu[])功能:将文件中的学生数据读入到学生记录表中,并返回表中的记录数。voidmenu()功能:显示系统提供的可选菜单项voidmain()整个系统的控制部分。三、详细设计及编码1、主函数的设计:启动程序后,首先从文件中将学生信息读入到结构数组或链表中,然后进入菜单界面供用户选择,根据选择项执行相应的操作,直到退出该管理系统。菜单界面如下:根据前面的基本流程设计出如下的主函数:清屏,原型包含在stdlib.h中voidmain(){structstudentstu[N];intlen;intchoice;charch;len=readfile(stu);//调用读文件函数cout按任意键继续endl;getchar();while(1)//注意该循环退出的条件{system(cls);//清屏函数menu();//调用菜单显示函数cout选择菜单项(0~8):;cinchoice;if(choice==0)//选择退出{cout\n保存到文件吗?endl;cinch;if(ch=='y'||ch=='Y')save(stu,len);cout\n欢迎再次使用,按任意键退出endl;getchar();break;}增强交互switch(choice){case1:display(stu,len);break;case2:search(stu,len);break;case3:len=append(stu,len);break;case4:len=del(stu,len);break;case5:modify(stu,len);break;case6:count(stu,len);break;case7:sort(stu,len);break;case8:save(stu,len);break;default:cout\n输入错误,按任意键继续endl;getchar();}}}2、menu函数的设计该函数功能很简单,只需在屏幕上按要求显示菜单项,请自行完成设计。3、display函数的设计分析:遍历长度为len的结构数组stu,输出每个学生的所有信息。注意对结构数组成员的访问层次,尤其是成员本身又为数组的学生成绩,需逐一访问。如第i个学生的第j门课的成绩需表示为:stu[i].s[j]故遍历需双重循环。voiddisplay(studentstu[],intlen){inti,j;if(len==0){cout无记录,按任意键返回endl;getchar();return;}cout学号\t姓名\t语文\t数学\t英语\t总分endl;for(i=0;ilen;i++){coutstu[i].num'\t'stu[i].name'\t';for(j=0;j3;j++)coutstu[i].s[j]\t;coutstu[i].s[0]+stu[i].s[1]+stu[i].s[2]endl;}cout按任意键继续endl;getchar();}对结构成员本身是数值型数组的访问方式4、search函数的设计设计思路:在长度为len的学生表中按姓名或学号查找指定的学生记录,因有不同的查询条件,所以需设计二级菜单,分别按学号和姓名查询学生记录,根据查询情况分别输出查询到的学生信息或是未找到的提示,然后返回到上级菜单。该函数的流程如下:开始选择查找方式按学号?选择错误否按姓名?否输入待查学号最后一个学生?是取第一个学生比较找到否?否否取下一个学生比较找到否?是输出未找到提示否输出找到的记录是结束同按学号查找过程,略voidsearch(studentstu[],intlen){intchoice,i,j;charnum[8],name[20];system(cls);cout1.按学号查询2.按姓名查询\n;cout输入查找方式[1,2]:;cinchoice;if(choice==1){cout输入学号:endl;cinnum;for(i=0;ilen;i++)if(strcmp(stu[i].num,num)==0){cout学号\t姓名\t语文\t数学\t英语\t总分endl;coutstu[i].num'\t'stu[i].name'\t';for(j=0;j3;j++)coutstu[i].s[j]\t;coutstu[i].s[0]+stu[i].s[1]+stu[i].s[2]endl;cout按任意键继续endl;getchar();return;}cout\n未找到该生记录,按任意键继续\n;getchar();return;}字符串比较必须通过此函数elseif(choice==2){cout输入姓名:endl;cinname;for(i=0;ilen;i++)if(strcmp(stu[i].name,name)==0){cout学号\t姓名\t语文\t数学\t英语\t总分endl;coutstu[i].num'\t'stu[i].name'\t';for(j=0;j3;j++)coutstu[i].s[j]\t;coutstu[i].s[0]+stu[i].s[1]+stu[i].s[2]endl;cout按任意键继续endl;getchar();return;}cout\n未找到该生记录,按任意键继续\n;getchar();return;}else{cout\n选择错误,按任意键返回endl;getchar();}}?思考:比较按姓名和学号两种方式查询的代码,函数如何优化更简洁5、append函数的设计设计思路:在学生表中添加新的学生记录。①首先输入要添加的学生学号,在原表中查找该学号的记录是否已存在。②若已存在,则选择是否重新输入新学生记录,如选择“是”,则返回①;否则结束函数返回主菜单。若原表中不存在该学号的学生,则继续输入要添加的学生的姓名和三门课的成绩。③添加成功后,学生表的实际长度增加1.intappend(studentstu[],intlen){inti;charnum[8],ch;system(cls);while(1){cout输入学号(输入'0'返回菜单):endl;cinnum;if(strcmp(num,0)==0)returnlen;for(i=0;ilen;i++){if(){cout学号num已存在,重试(y/n):;cinch;if(ch=='y'||ch=='Y');else{cout按任意键返回endl;getchar();returnlen;}}}strcmp(stu[i].num,num)==0breakif(i==len)//要添加的学生记录不在原表中break;}strcpy(stu[len].num,num);cout输入姓名:endl;cinstu[len].name;cout输入语文成绩【0~100】:endl;cinstu[len].s[0];cout输入数学成绩【0~100】:endl;cinstu[len].s[1];cout输入英语成绩【0~100】:endl;cinstu[len].s[2];;returnlen;}len++?思考:该函数的类型为何要定义为int类型6、del函数的设计设计思路:为简单起见,本例中该函数只考虑按学号删除的情况,实际应用中还可按姓名删除学生记录。本例中该函数的设计思路:①若学生表为空表,则做相应的提示,然后退出该函数;若非空,则转②②在表中查找待删除学生的学号。③若找到,该学生后的所有记录前移一位删除该记录,然后退出该函数;若未找到,则提示该学生不存在,重新输入新学号后,转②继续查找。注意:因该函数会改变学生表的实际长度,所以函数返回值设计为int类型。int