简易评分系统程序设计说明书.docx
《简易评分系统程序设计说明书.docx》由会员分享,可在线阅读,更多相关《简易评分系统程序设计说明书.docx(29页珍藏版)》请在冰点文库上搜索。
简易评分系统程序设计说明书
●概述
程序名称:
简易评分系统
开发平台:
Windows7
VC++6.0
主要功能:
1.管理员界面
(1)于程序中设置评委信息
(2)从文件导入评委信息
(3)于程序中设置参赛者信息
(4)从文件导入参赛者信息
(5)导出赛果到文件
2.评委界面
(1)显示参赛者列表与评分
(2)根据名次显示赛果
(3)根据名称显示赛果
3.参赛者界面:
显示自己的最终成绩
程序说明:
该程序根据使用者身份分为三个可执行文件独立运行
该程序于使用期间可根据需要打开或退出而不会丢失中间数据,除非使用者自行更改程序运行时生成的文件。
管理员密码固定为administrator
程序所有相关文件需置于同一目录下
运行环境:
win7
文件说明:
1.源代码
(1)管理员相关函数:
adm_function.h
(2)评委相关函数:
jdg_function.h
(3)参赛者相关函数:
cmpt_function.h
(4)数据读写相关函数与数据结构:
data.h
(5)管理员界面源文件:
adm.cpp
(6)评委界面源文件:
jdg.cpp
(7)参赛者界面源文件:
cmpt.cpp
2.程序执行文件
(1)管理员界面:
adm.exe
(2)评委界面:
jdg.exe
(3)参赛者界面:
cmpt.exe
3.主要数据存储文件
(1)评委信息:
jdg.dat
(2)参赛者信息:
cmpt.dat
(3)赛果:
result.dat
●程序设计概要
⏹数据读写相关函数与数据结构头文件
包含头文件
#include//文件读写
#include//C语言标准输入输出
#include//字符串比较
数据结构
structjudge//评委
{
intj_id;//评委编号
charname[20],password[20];
};
structcompetitor//参赛者
{
intc_id;//参赛者编号
charname[20],password[20];
floatscore;
intranking;//排名
};
函数
1.voidscoring_mtrx()
该函数生成一个二维数组[jdg_num][cmpt_num]用于保存评分过程并以二进制文件形式保存于外存
2.voidcmpt_counter()voidcmpt_counter(intcmpt_id)
该函数生成数组[cmpt_num],标识某参赛者已被多少位评委评分并输出到文件cmpt_counter.dat
文件开头有评委与参赛者的人数供判断评分是否已全部结束
函数有重载,一个参数为无参,用于管理员完成人数设置后初始化cmpt_counter.dat用,另一个参数为(cmpt_id)用于在评分时更新cmpt_counter.dat数据用
3.voidjdg_counter()voidjdg_counter(intjdg_id)
该函数生成数组[jdg_num],标识某位评委已对多少位参赛者评分,数据输出保存到jdg_num.dat
该函数同样有一重载用于评分时更新jdg_counter.dat的数据
4.voidsorting()
该函数用于对参赛者成绩进行排序
5.intif_end()
该函数用于判断所有评委的评分工作是否已经完成
⏹管理员界面相关函数与流程
包含头文件
#include"data.h"
函数
1.voidadm_log()
管理员登陆界面
2.voidadm_in()
管理员登入后的界面
3.voidset_jdg()
设置评委数据
4.voidjdg_fromfile(intn,judge*p)
从文件导入评委数据(被set_jdg()调用)
5.voidjdg_inprgrm(intn,judge*p)
在程序中设置评委数据(被set_jdg()调用)
6.voidset_cmpt()
设置参赛者数据
7.voidcmpt_fromfile(intn,competitor*p)
从文件导入参赛者数据(被set_cmpt()调用)
8.voidcmpt_inprgrm(intn,competitor*p)
在程序中设置参赛者数据(被set_cmpt()调用)
9.voidto_file()
导出赛果到文件
大致流程
1.程序运行后会检查是否有jdg.dat与cmpt.dat
2.若无以上两文件则提示设置评委与参赛者
3.若已存在以上两文件则判断评分工作是否已经完成
4.若否则提示管理员在评分工作完成后登陆
5.若是则提示导出赛果到文件
⏹评委界面相关函数与流程
包含头文件
#include"data.h"
#include//fflush(stdin)清除输入缓冲区残余数据
函数
1.voidshow_by_name(intjdg_id)
根据名字显示赛果
2.voidcmpr(intc,inti,char**p_p)
用于show_by_name函数排列参赛者名字顺序时调用
3.voidshow_by_score(intjdg_id)
根据名次显示赛果
4.voidshow_cmpt(intjdg_id)
显示参赛者列表以及该评委对各个参赛者的评分
5.voidjdg_log()
评委登陆界面
6.voidjdg_in(intjdg_id)
评委登入后的界面
大致流程
1.程序运行后检查管理员是否已经完成评委设置
2.若否则退出程序
3.若管理员已完成设置则输出提示:
1.显示参赛者列表与评分
2.根据名次显示赛果
3.根据名称显示赛果
4.若选择1则检查该评委是否已完成评分工作
5.若已完成则输出提示并显示该评委对所有选手的评分
6.若否则提示输入选手编号进行评分
7.若选择2与3则检查所有评委是否都已完成评分工作
8.若否则输出提示信息
9.若已完成则根据评委要求对选手进行排序并输出
⏹参赛者界面相关函数与流程
包含头文件
#include"data.h"
函数
1.voidcmpt_login()
参赛者登陆
2.voidshow_score(intcmpt_id)
显示登陆的参赛者的最终成绩与排名
大致流程
1.程序运行后检查管理员是否已经完成初始化设置
2.若未完成则输出提示信息
3.若已完成则检查所有评委的评分工作是否已经完成
4.若是则输出该参赛者的最终成绩
5.若否则输出提示信息
●关键代码分析
⏹管理员初始化设置
程序提供两种方式进行评委与参赛者的初始化设置,若选择于程序中输入初始化数据,则完成输入后程序后生成jdg.dat与cmpt.dat。
jdg.dat的格式为:
评委人数
编号名称密码
编号名称密码
编号名称密码
…
…
cmpt.dat的格式为:
参赛者人数
编号名称密码分数排名
编号名称密码分数排名
…
…
若选择从文件导入,则需事先准备set_jdg.dat与set_cmpt.dat两个文件
格式都为:
人数
名称密码
名称密码
名称密码
…
…
无论采用哪种方式,程序最后都会将管理员设置的用户信息输入(从键盘输入或从文件输入)到一个结构体数组并利用此结构体生成jdg.dat与cmpt.dat。
生成jdg.dat与cmpt.dat的主要代码如下:
fstreamoutfile("jdg.dat",ios:
:
out);或fstreamoutfile("cmpt.dat",ios:
:
out);
outfile<for(i=0;ioutfile<j_id<<""或outfile<c_id<<""
<name<<""<name<<""
<password<password<<""
if(ip_jdg++;或p_cmpt++;
}
outfile.close();
⏹用户名与密码核对
该模块根据使用界面不同由voidjdg_log()、voidadm_log()、voidcmpt_login()分别实现核对功能。
管理员界面直接核对密码(administrator),评委与参赛者界面则通过载入包含所有用户的用户名与密码的jdg.dat或cmpt.dat文件,对使用者输入的信息进行核对,该模块每次提供给使用者的输入机会为3次,错误达到3次则自动退出程序。
管理员模块的密码核对代码
voidadm_log()
{
charadm_pswrd[14]="administrator";//程序中管理员密码固定为administrator
staticintpswrd_c=3;//剩余输入密码次数
cout<cout<<"输入密码:
";
charp[14];
cin>>p;
cout<if(strcmp(p,adm_pswrd)==0)//密码验证
adm_in();//若密码正确则调用adm_in()函数进入管理员界面
else{
pswrd_c--;//若密码错误则减少一次密码输入的机会
if(pswrd_c==0)
;//若输入错误达3次则通过执行空语句退出管理员界面
else{
若密码错误但仍有输入密码的机会则显示提示信息;
adm_log();
}
}
}
该段代码通过函数adm_log()的自我递归调用实现为用户提供3次输入密码的机会,计数器为adm_log()内定义的一个静态整型变量。
评委/参赛者模块的用户名与密码核对代码
评委模块与参赛者模块的登陆核对代码相似,故只列出评委部分的主要代码,另外用一些自然语句描述代替了部分代码(^_^)
该部分通过for语句实现3次机会输入,验证用户名用一个for语句,验证密码则用另一个for语句嵌套于“用户名验证for语句”中,在“用户名验证for语句”中,若核对得使用者输入的用户名正确,则执行“密码验证for语句”,通过goto语句实现
{
先将jdg.dat文件载入程序并动态新建一结构体数组用于保存文件信息;
}
for(intusrnm_c=1;usrnm_c<=3;usrnm_c++){
cout<<"输入用户名:
";
cin>>name;
for(i=0;i<=jdg_num;i++){//验证用户名是否存在
if(strcmp(name,p_jdg->name)==0){//用户名正确则输入密码
charpassword[20];
for(i=3;i>0;i--){//3次机会输入密码
cout<<"输入密码:
";
cin>>password;
if(strcmp(password,p_jdg->password)==0){//密码正确
intjdg_id;//该评委的编号
jdg_id=p_jdg->j_id;
jdg_in(jdg_id);
gotoexit;
}
else{
输出密码错误提示信息;
continue;//再给次输入的机会(^_^)
}
}
gotoexit;//三次错误则强制退出
}
if(ip_jdg++;
}
输出用户名错误提示信息;
for(i=0;ip_jdg--;
}
exit:
;
编写该模块时曾出现定义的变量被goto跳过的情况,查得是if语句缺少了一个结尾花括号。
另外编写过程中曾忘记将指针复位导致测试的输出显示为乱码甚至导致操作系统不给运行程序(没复位的指针直接进入下一个for语句不断+1+1+1最后指到哪里去都不知道),这个debug了好久才找到原因,一开始我还怀疑是win7对VC的兼容不良导致的。
呵呵呵……=_=!
,后来的代码我就不采用直接增加指针值的方法了,而是*(p+c),用另一个变量c来表示指针要移动的相对位移,连复位都不用了(^_^)
⏹评分过程中的数据读写
除了jdg.dat和cmpt.dat之外,管理员完成初始化设置后,程序还会生成scoring_mtrx.dat、jdg_counter.dat和cmpt_counter.dat三个文件。
scoring_mtrx.dat
scoring_mtrx.dat为一关系矩阵[numofjdg][numofcmpt]记录某位评委对某位选手的评分,该文件用二进制形式存储。
该文件所有元素在初始化都置0。
评委进行评分工作时,程序会读取该文件并将其内容载入一个二维数组中用于记录该评委对所有选手的打分。
评委每对一位选手进行评分,程序就会更新一次scoring_mtrx.dat文件的内容。
因此即便评分过程被打断,程序被关闭也不会导致评委的工作进度丢失。
该文件也用于程序中评委查看自己对所有选手的打分情况。
初始化scoring_mtrx.dat文件的函数voidscoring_mtrx()主要代码如下:
//动态定义大小为[jdg_num][cmpt_num]的矩阵
float**p_mtrx;
p_mtrx=newfloat*[jdg_num];
for(intj=0;j*(p_mtrx+j)=newfloat[cmpt_num];
//置0初始化并输出到文件'scoring_mtrx.dat'
for(j=0;jfor(intc=0;c*(*(p_mtrx+j)+c)=0;
}
}
for(j=0;jfor(intc=0;cscoring_mtrx.write((char*)&*(*(p_mtrx+j)+c),4);
}
}
scoring_mtrx.close();
评委评分过程中程序更新scoring_mtrx.dat的代码如下:
事先动态定义大小为[jdg_num][cmpt_num]的二维数组,将scoring_mtrx.dat文件的内容载入该数组,然后在数组中修改指定元素的值(即某一评委对某一选手的打分)
cin>>*(*(p_mtrx+jdg_id)+cmpt_id);//cmpt_id由评委输入,jdg_id为该评委的编号
然后在用下列代码将数组的内容覆盖进文件scoring_mtrx.dat
file.open("scoring_mtrx.dat",ios:
:
binary|ios:
:
out);
for(j=0;jfor(c=0;cfile.write((char*)&*(*(p_mtrx+j)+c),4);
}
}
file.close();//至此scoring_mtrx.dat更新完成
通过编写这段代码使我基本掌握如何编写代码对二进制文件进行特定位置的读写
jdg_counter.dat和cmpt_counter.dat
当选手在评分未结束时登陆查看、评委在其它评委未完成工作时要求查看赛果、管理员在评分未结束时试图导出赛果时,就需要程序能对人们的工作进度进行判断并显示相应信息。
这就需要jdg_counter.dat和cmpt_counter.dat两个文件。
这两个文件保存的数据都为一维数组。
jdg_counter.dat数组的每个元素分别代表每个评委已打分的参赛者人数
cmpt_counter.dat数组的每个元素分别代表每个参赛者已被多少位评委打分
若jdg_counter.dat的每个元素都等于参赛者总人数、cmpt_counter.dat的每个元素都等于评委总人数,那么就表示评分工作已经结束。
jdg_counter.dat和cmpt_counter.dat在管理员界面分别由无参函数cmpt_counter()和
jdg_counter()对所有数组元素进行置0初始化,jdg_counter.dat开头有一个整数表示评委总人数,cmpt_counter.dat开头有两个整数分别表示评委总人数和参赛者总人数。
初始化jdg_counter.dat的函数的代码如下:
voidjdg_counter()
{
intjdg_num;
fstreamfile("jdg.dat",ios:
:
in);//从jdg.dat文件获取本次比赛的评委总数
file>>jdg_num;
file.close();
file.open("jdg_counter.dat",ios:
:
out);
file<for(intj=0;jfile<<0<file.close();
}
初始化cmpt_counter.dat的函数的代码如下:
voidcmpt_counter()
{
intjdg_num,cmpt_num;
fstreamfile("jdg.dat",ios:
:
in);
file>>jdg_num;//获取本次比赛的评委总数
file.close();
file.open("cmpt.dat",ios:
:
in);
file>>cmpt_num;//获取本次比赛的参赛者总数
file.close();
file.open("cmpt_counter.dat",ios:
:
out);
file<file<for(intc=0;cfile<<0<file.close();
}
jdg_counter.dat和cmpt_counter.dat在管理员界面初始化,在评委界面进行数据更新,更新数据由初始化文件的函数的重载函数进行
更新jdg_counter.dat的函数代码如下:
voidjdg_counter(intjdg_id)//jdg_id为评委编号,用于确定要更新文件中哪个评委的数据
{
intpass,counter;//pass用于跳过不需要修改的元素,counter用于修改目标元素
fstreamfile("jdg_counter.dat",ios:
:
in);
file>>pass;//跳过jdg_num项
for(intj=0;jfile>>pass;//跳过其它评委的jdg_counter
//载入该评委的jdg_counter
file>>counter;
file.close();
//更新该评委的jdg_counter
counter++;//将该jdg_counter值加1
file.open("jdg_counter.dat",ios:
:
in|ios:
:
out);
//将修改后的数值保存入文件
for(j=0;j<=jdg_id;j++)
file>>pass;
file<file.close();
}
voidcmpt_counter(intcmpt_id)的实现方式与以上函数相同,代码类似,故在此略过(^_^)
可以看到,所谓的更新jdg_counter.dat和cmpt_counter.dat文件其实就是将文件中特定元素在原来的数值基础上加1,识别特定元素的参数在评委界面模块代码中给出。
评委在对任一选手进行评分前都得输入该选手的编号,参数cmpt_id来自于评委的输入。
至于参数jdg_id:
在这份说明书的“程序设计概要”的“评委界面相关函数与流程”处可看到该模块很多函数都带有参数jdg_id。
在评委登陆界面函数jdg_log()验证得使用者身份合法后会调用进入评委界面的函数jdg_in(intjdg_id),然后再根据使用者的输入由jdg_in(intjdg_id)函数调用实现相应功能的函数,参数jdg_id便是由jdg_in(intjdg_id)开始传递给其它需要该参数的函数。
在此附上jdg_in函数的代码:
voidjdg_in(intjdg_id)
{
printf("╔═════════════╗\n");
printf("║1.显示参赛者列表与评分║\n");
printf("║2.根据名次显示赛果║\n");
printf("║3.根据名字显示赛果║\n");
printf("║0.退出登录║\n");
printf("╚═════════════╝\n");
intswtch;
swtch=getch()-48;
while(swtch>3){
cout<<"请输入正确指令!
"<swtch=getch()-48;
}
switch(swtch){
case1:
show_cmpt(jdg_id);break;//修改两个counter文件的两个函数便是
case2:
show_result(jdg_id);break;由这个函数调用的
case3:
show_by_name(jdg_id);break;
case0:
jdg_log();
}
}
⏹评分过程中特定状态的判定
判断某一参赛者是否已被某一评委评分
该功能的实现需要scoring_mtrx.dat文件
判断某一参赛者是否已被该评委评分,只需在程序中读取scoring_mtrx.dat文件特定位置的元素,若该元素值非0,则表明该参赛者已被该评委评分,否则元素值为0。
用于判断的if语句如下(文件的内容保存于一个二维数组中):
if(*(*(p_mtrx+jdg_id)+cmpt_id)!
=0)//p_mtrx是动态建立的二维数组的指针
若某一评委试图对某一选手重复打分则会显示相应提示信息
判断任一评委的工作是否已结束
该功能的实现需要jdg_counter.dat文件