综合性实验:小学生成绩管理系统
实验学时:4学时
涉及的知识点:分支语句、循环、分类统计、结构体、函数、文件操读写,记录的排序、增删改查等操作
一、实验目的
综合应用分支语句、循环、结构体、函数、文件操读写、排序sort命令排序等知识,实现一个小学生成绩管理系统的程序。
(1)掌握结构体的类型声明、变量定义与初始化;
(2)掌握函数的声明、定义和调用,能够正确理解、使用指针作参数的函数;
(3)理解模块化程序设计的要点:把一个较大的程序模块划分为若干小模块,小模块包含一个或多个函数,每个函数实现一个特定的功能,main函数起主控作用;
(4)熟悉控制台环境下菜单设计的基本思路,并能通过菜单的选择调用相应函数模块;
(5)掌握文本文件的打开、读取、写入、关闭等操作;
(6)熟悉记录的排序、增删改查操作的基本思路。
二、实验内容
某小学要求在学生考试结束后,对考试成绩进行简单的处理和统计。功能包括:成绩的输入、删除、修改、查、排序、统计、保存到文件等。学生的考试科目有:语文、数学和外语三科。学生基本信息包含:学号、姓名两项。学生总人数不超过1000人。一个学生的所有信息(包括基本信息、成绩等)为一条记录。
主要功能列举如下:
(1)输入若干条学生成绩记录(包括学号、姓名、各科成绩)。
(2)显示所有记录。
(3)计算每个学生的总分。
(5)按姓名查并显示相应的记录。
(6)按学号查并删除相应的记录。
(7)输出各个科目的统计信息(最高分、平均分、及格率、优秀率等)。
(8)将数据保存到文本文件中。
(9)从文本文件中读取数据。
三、实验器材设备
安装了WindowsXP(或其他版本的Windows操作系统)和VS2010(或以上版本的Visusl Studio版本)的PC机一台。
四、实验要求
(1)主要的数据存储方式
该程序主要处理学生成绩。学生成绩数据比较多,而每个学生的信息都具有相同的结构,这种情况最适宜采用结构体数组进行存储。因为已经知道学生人数不超过1000人,所以只
需要定义元素个数为1000的结构体数组即可。为了适当增加灵活性,可以将学生人数的最大值定义为一个常数。如果学生人数不能预测,则需要利用动态内存分配技术和链表等,复杂度会增加。
结构体定义:注意包含学生基本信息、三科成绩,另外还要一个总分字段。
#define MAX_STUDENT_COUNT 1000
typedef struct /*定义结构体数组*/
{
int num; /*学号*/
char name[20]; /*姓名*/
double chi; /*语文*/
double math; /*数学*/
double eng; /*英语*/
double total; /*总分*/
}Student;
Student Stud[MAX_STUDENT_COUNT]; /* 结构体数组变量 */
int Student_Count; /* 学生记录数 */
由于整个程序功能主要就是围绕这个结构体数组进行,为了减少参数的传递,可以将变量定义为全局变量。
(2)主菜单设计
程序的功能比较多,为了方便用户操作,常用的方式是在进入程序后提供一个主菜单(列出程序提供的功能),让用户可以通过直观的方式选择要执行的功能。
主菜单的设计要注意,应该包含所有的系统功能,并且有快捷键执行相应的菜单。
根据本程序的功能,可以设计如图1所示的主菜单:
图1系统主菜单示图
用户在执行完一个功能后,往往还要继续执行另一个功能。此时需要循环地显示主菜单,输入用户的选择,并执行相应的功能。一般使用如下的循环实现:
while(choice!='q')
{
//显示主菜单
choice = getchar();
switch(choice)
{
case '1'://执行功能1
break;
case '2'://执行功能2
break;
...
case '0':
}
}
设计好菜单显示的内容之后,只需要直接显示出来即可。
(3)数据的显示
在程序的多处地方都需要显示数据,一些地方需要显示多条记录,而另外一些地方则需要显示单条记录。该程序对多条记录和单条记录均采用统一的输出格式,方便了程序的编写。
显示方法为首先显示统一的表头,然后依次显示每一条记录的内容。
(4)文本文件格式的设计
程序需要输出数据到文本文件中,并且要求还能够从文本文件中读取数据。如果设计不合理,会导致生成的数据文件无法正确读取出来等问题。
为了方便数据的写入和读取,这里采用文本文件格式。格式如下:
<记录总数>
<学号>
<姓名>
<语文>,<数学>,<英语>
...
<学号>
<姓名>
<语文>,<数学>,<英语>
例如:一个数据文件内容
3
100
Zhang3
98,67,53
101
Li4
65,92,84
102
Wang5
93,84,97
文本数据文件的生成和读取都按照这一格式来进行,在文本文件的最开始处放置记录的个数,是为了方便数据的读取。
(5)使用fflush()函数清空文件缓冲区
程序经常需要从键盘读入一个字符的命令。如果在getchar()之前,输入缓冲区中还有一些未被读取的字符,会导致getchar()直接读取用户以前输入的尚未被读取的字符,甚至包括
用户输入的回车符。因此,在需要获取用户最新输入的字符时,需要首先清空标准输入文件(stdin, 一般对应输入的键盘)输入缓冲区的内容。
清空键盘输入缓冲区的方法是调用fflush(stdin)。stdin是预先打开的标准输入文件的文件指针。
(6)程序主要函数原型和说明
1)voiddisplay_menu()
功能:显示系统的主菜单。
2) voiddisplay_header()
功能:显示记录的标题。
3) voiddisplay_a_record(Student *pstud)
功能:显示一条记录的记录体。通过结构体指针传递参数,可以减少参数传递的开销。
4) voiddisplay_all_record()
功能:显示全局变量中的所有记录。实现主菜单中“显示所有记录”的功能。
5) Student input_a_record()
功能:输入单个学生的记录,并返回该记录。
6)voidinput_record()
功能:添加记录。函数会循环提示用户输入学生信息,并逐条记录添加到全局结构体数组变量Stud中。实现主菜单中“添加记录”的功能。
7)voidcalc_total()
功能:计算所有记录的总分。总分为三科成绩的和。在显示记录和排序之前,都需要计算总分。
8)voidsort_by_num()
功能:按学号排序。将学生记录按照学号由小到大的顺序排列。
9)voidsort_by_total()
功能:按总分排序,将学生记录按照总分由大到小的顺序排列。
10) intDelete_record_by_num(intnum)
功能:在学生记录中删除学号为num的记录。
11)voidDelete_a_record()
功能:删除记录。首先输入要删除的学生的学号,然后删除该学号对应的学生记录。对应主菜单“删除记录”的功能。
12) Student *query_a_record_by_name(char *name)
功能:在学生记录数组中查指定姓名的学生记录。如果到,则返回该记录的指针,否则返回空指针NULL。
13)voidquery_a_record()
功能:输入一个学生的姓名,到并显示匹配的学生记录。
14)void Statistic()
功能:计算并输出所有学生记录的统计值,主要包括各科平均分和最高分。
15)voidread_textfile()
功能:从文本文件中输入学生记录。
16) voidwrite_textfile()
功能:将所有记录输出到文本文件中。
七、实验报告要求
实验报告除必备的实验目的、实验要求等要素外,应包含以下内容:
(1) 说明程序测试的过程和结果;
答:复制相应的代码到C程序,检查代码是否错误,然后完善功能3~9,不断的调试不断的修改,只到程序能执行且能执行全部功能才可以。
(2) 说明程序的运行流程;
答:先显示菜单,清空输入缓冲区,输出0~9的数字,switch 到相应的数字功能,执行该功能,然后void display_all_record():显示全局变量中的所有记录。实现主菜单中“显示所有记录”,然后break,清除输入缓冲区后,输入0结束程序。
(3) 完善功能3~功能9的代码段内容;
//功能4(按学生总分从大到小排序)
voidsort_by_total()
{ inti,j;
Student t;
for(i=0;i<Student_Count-1;i++)
for(j=0;j<Student_Count-1-i;j++)
if(Stud[j].total< Stud[j+1].total)
{
t = Stud[j+1].total;
Stud[j+1].total = Stud[j].total;
Stud[j].total = t;
}
//功能6(成绩查询),输入一个学生的姓名,输出姓名相匹配的学生记录
//先完成如下函数的定义,再调用相关函数实现上述功能
Student *query_a_record_by_name(char *name)
{int *p;
p=&(Stud[i].name;
for(inti=1;i<Student_Count;i++)
{ if (p== name)
display_header()
display_a_record(p);
}
}
//完善功能7(“成绩统计”),增加计算并显示各科及格率和优秀率的功能。
{ int i,c1,c2,m1,m2,e1,e2; float j.chi,j.,y.chi,y.;
for(i=0; i<Student_Count; i++)
{ if(Stud[i].chi>=60) c1++;
if(Stud[i].math>=60) m1++;
if(Stud[i].eng>=60) e1++;
if(Stud[i].chi>=80) c2++;
if(Stud[i].math>=80) m2++;
if(Stud[i].eng>=80) e2++;
}
j.chi=c1/ Student_Count; J.math=m1/ Student_Count; J.eng=e1/ Student_Count; /*及格率 */
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论