1 需求分析
大学生考勤是治理工作的重要内容,同时也是学校治理的重要组成部分,通过和指导老师交流,了解到本系统中的数据源于标准输入设备(如键盘),或者来自某文件,可以实现对大学生考勤信息的添加,根据需要也可查询用户所需的学生考勤信息、删除无价值的信息、修改错误的信息等,总之本系统,要具备如下功能:添加信息、查询信息、删除信息、修改信息、将信息排序、显示所有信息、数据统计、退出和保存信息,能够通过本系统便利的实现对学生考勤情况的把控,要求操作界面友好,便捷,有一定的容错率。
2 概要设计
- 数据组织
使用结构体数组临时存储每个学生信息和考勤情况,利用文件存储,达到对学生信息的永久记录。定义Enter()函数实现回车键返回菜单的功能,定义copy函数使两个学生信息进行交换,定义judge函数判断系统中是否已存在此学生,定义ADD()函数添加学生信息,定义find()函数查找学生信息,定义change()函数修改学生信息,定义Delete()函数删除学生信息,定义Print()函数打印学生信息,定义data()函数打印所需资料表。定义paixv()函数实现用姓名或学号对学生进行排序。
- 功能模块
需要实现的功能:
(1)新增学生信息数据。
(2)数据的查找。
(3)学生记录的修改。
(4)学生记录的删除。
(5)显示学生考勤数据列表。
(6)学生信息排序。
(7)数据统计。
(8)保存数据到文件中并从文件中读入数据。
3 运行环境(软、硬件环境)
1.硬件环境:PC机-内存 16GB。
2.软件环境:操作系统-windows10。
4 开发工具和编程语言
开发环境:Dev-C++5.11。
编程语言:C语言。
5 详细设计
本系统实现了新增学生信息数据、数据的查找、学生记录的修改、学生记录的删除、显示学生考勤数据列表、学生信息排序、数据统计。具体展示如下:
5.1 新增学生数据
新增学生数据功能,需要输入学生的学号,如果学号已存在,显示此人已存在。如果学号不存在,输入学生姓名、班级、考勤日期和考勤结果。具体代码如下所示:
void ADD(){
char ID[maxsize];
printf("请输入学生的学号:");
scanf("%s",ID);
if(!judge(ID)){
printf("此人已存在\n");
printf("请按回车键返回\n");
Enter();
return;
}
strcpy(students[num].studentID,ID);
shuru("请输入学生的姓名:",students[num].Name);
shuru("请输入学生的班级:",students[num].classNumber);
shuru("请输入学生的考勤日期:",students[num].date);
shuru("请输入学生的考勤结果:出 勤 √ 旷 课 X 事 假 ▲ 病 假 ● 迟 到 + 早 退 –",students[num].result);
num++;
printf("添加成功!按回车键返回\n");
Enter();
}
5.2 查找学生数据
查找学生数据功能,选择按学号查找或按姓名查找,输入学号或姓名。如果存在此学生,打印学生信息。如果不存在此学生,显示不存在此信息。具体代码如下所示:
void find(){
int i,op,flag=-1;//flag是是否查找到的标识
char information[maxsize];
printf("<1>按学号查找 <2>按姓名查找");
scanf("%d",&op);
if(op==1){
printf("请输入该生学号:");
scanf("%s",information);
for(i=0;i<num;i++){
if(strcmp(information,students[i].studentID)==0)
{
printf("%s %s %s %s %s\n\n",students[i].studentID,students[i].Name,students[i].classNumber,students[i].date,students[i].result);
flag=1;
}
}
}
else if(op==2){
printf("请输入该生姓名:");
scanf("%s",information);
for(i=0;i<num;i++){
if(strcmp(information,students[i].Name)==0)
{
printf("%s %s %s %s %s\n\n",students[i].studentID,students[i].Name,students[i].classNumber,students[i].date,students[i].result);
flag=1;
}
}
}
if(flag==-1)//没有找到该学生
printf("不存在此信息\n");
printf("查找完成!按回车键返回\n");
Enter();
}
5.3 修改学生记录
修改学生记录功能,先选择按学号查找或按姓名查找所要修改记录的学生。如果存在此学生,选择修改该生的姓名或学号。如果不存在此学生,显示不存在此信息。具体代码如下所示:
void change(){
int i,j=-1;
char op[2],information[maxsize],find[maxsize];
printf("<1>按学号查找 <2>按姓名查找\n");
scanf("%s",op);
if(op[0]=='1'){
shuru("请输入该生学号",information);
}
else if(op[0]=='2'){
shuru("请输入该生姓名",information);
}
if(op[0]=='1'){
for(i=0;i<num;i++)
if(strcmp(information,students[i].studentID)==0) j=i;
}
else if(op[0]=='2'){
for(i=0;i<num;i++)
if(strcmp(information,students[i].Name)==0) j=i;
}
if(j==-1){
printf("不存在要找的信息!\n");
printf("按回车键返回\n");
Enter();
return;
}
shuru("请输入修改后的新学号:",information);
strcpy(students[j].studentID,information);
shuru("请输入修改后的新姓名:",information);
strcpy(students[j].Name,information);
shuru("请输入修改后的新班级:",information);
strcpy(students[j].classNumber,information);
shuru("请输入修改后的考勤日期:",information);
strcpy(students[j].date,information);
shuru("请输入修改后的考勤结果:出 勤 √ 旷 课 X 事 假 ▲ 病 假 ● 迟 到 + 早 退 –",information);
strcpy(students[j].result,information);
printf("修改完成!按回车键返回!\n");
Enter();
}
5.4 删除学生记录
删除学生记录功能,先选择按学号删除或按姓名删除。如果存在此学生,删除成功。如果不存在此学生,显示不存在此信息。具体代码如下所示:
void Delete(){
int i,j,flag=-1;
char op[2],information[maxsize];
shuru("请输入:<1>按学号删除<2>按姓名删除", op);
if(op[0]=='1') {
shuru("请输入学号:",information);
for(i=0;i<num;i++){
if(strcmp(information,students[i].studentID)==0){
flag=1;
for(j=i;j<num;j++){
copy(&students[j],&students[j+1]);
}
}
}
}
else if(op[0]=='2') {
shuru("请输入姓名:",information);
for(i=0;i<num;i++){
if(strcmp(information,students[i].Name)==0){
flag=1;
for(j=i;j<num;j++){
copy(&students[j],&students[j+1]);
}
}
}
}
if(flag==-1){
printf("不存在此信息!\n");
printf("按回车键返回\n");
Enter();
return;
}
else {
num--;
printf("删除完成!按回车键返回\n");
Enter();
}
}
5.5 打印学生考勤数据列表
打印学生考勤数据列表功能,选择部分打印或全部打印,选择部分打印会输出学生姓名和考勤日期和考勤情况。选择全部打印会输出所有学生的所有信息。具体代码如下所示:
void Print(){
int op;
printf("请选择\n<1>部分打印(输出学生姓名和考勤日期和考勤情况)\n<2>全部打印(输出所有学生的所有信息):");
scanf("%d",&op);
if(op==1){
shuchuPart();
}
else{
shuchuAll();
}
}
void shuchuAll(){
int i;
printf("------------------------------------\n");
for (i = 0; i < num; i++)
printf("%s %s %s %s %s\n", students[i].studentID,students[i].Name,students[i].classNumber,students[i].date,students[i].result);
printf("------------------------------------\n");
printf("打印成功!按回车键返回\n");
Enter();
}
void shuchuPart(){
int i;
printf("------------------------------------\n");
for (i = 0; i < num; i++)
printf("%s %s %s\n",students[i].Name,students[i].date,students[i].result);
printf("------------------------------------\n");
printf("打印成功!按回车键返回\n");
Enter();
}
5.6 对指定数据进行排序
对指定数据进行排序功能,选择按学号从小到大排序或按学生姓名ASCII码进行排序。具体代码如下所示:
void paixv(){
int op,i,j;
char tmp[maxsize];
printf("请输入:<1>按学号从小到大排序 <2>按学生姓名ASCII码排序\n");
scanf("%d",&op);
if(op==1){
for(i=0;i<num;i++){
for(j=i+1;j<num;j++){
if(strcmp(students[i].studentID,students[j].studentID)>0){
exchange(&students[i],&students[j]);
}
}
}
}
else if(op==2){
for(i=0;i<num;i++){
for(j=i+1;j<num;j++){
if(strcmp(students[i].Name,students[j].Name)>0){
exchange(&students[i],&students[j]);
}
}
}
}
printf("排序成功!按回车键返回\n");
Enter();
}
5.7 进行数据统计
进行数据统计功能,选择打印考勤日报表、考勤异常表、请假汇总表。选择打印考勤日报表后输入要打印的考勤日期,完成打印。选择打印考勤异常表会打印除考勤状态为出勤外的所有人。选择打印请假汇总表会打印所有请假的人。具体代码如下所示:
void data(){
char op[2];
shuru("请输入\n<1>考勤日报表\n<2>考勤异常表\n<3>请假汇总表",op);
if(op[0]=='1'){
daily();
}
else if(op[0]=='2'){
kaoqin();
}
else if(op[0]=='3'){
qingjia();
}
}
void daily(){
int i;
char information[maxsize];
shuru("请输入要查看的日期:",information);
printf("------------------------------------\n");
printf("%s的考勤情况:\n",information);
for(i=0;i<num;i++){
if(strcmp(information,students[i].date)==0){
printf("%s %s %s %s\n",students[i].studentID,students[i].Name,students[i].classNumber,students[i].result);
}
}
printf("------------------------------------\n");
printf("打印成功!按回车键返回\n");
Enter();
}
void kaoqin(){
int i,cnt=0;
printf("------------------------------------\n");
printf("考勤异常表\n");
for(i=0;i<num;i++){
if(strcmp(students[i].result,"√")!=0)
{
printf("%s %s %s %s %s\n",students[i].studentID,students[i].Name,students[i].classNumber,students[i].date,students[i].result);
cnt++;
}
}
printf("考勤异常人数%d人\n",cnt);
printf("------------------------------------\n");
printf("打印成功!按回车键返回\n");
Enter();
}
void qingjia(){
int i,cnt=0;
printf("------------------------------------\n");
printf("请假异常表\n");
for(i=0;i<num;i++){
if(strcmp(students[i].result,"●")==0||strcmp(students[i].result,"▲")==0)
{
printf("%s %s %s %s %s\n",students[i].studentID,students[i].Name,students[i].classNumber,students[i].date,students[i].result);
cnt++;
}
}
printf("请假人数:%d人\n",cnt);
printf("------------------------------------\n");
printf("打印成功!按回车键返回\n");
Enter();
}
6 调试分析
问题1:如何让用户在输入结束后按回车键返回,更好的实现用户交互?
解决:放入两个getchar(),一个吸收选择功能时输入的回车,一个实现回车键返回。
问题2:C语言没有布尔类型,怎么用true和false来表示真假?
解决:引入头文件<stdbool.h>。
心得体会
程序设计基础这门课程对我来说是收获匪浅的一门课程,通过对基础理论知识的学习和实验及作业的训练,逐步对课程有了由浅入深的认识。通过完成这次《程序设计实践》课程设计,让我深刻认识到学习程序设计不能停留在学习它的语法规则,而是要利用学到的知识编写程序,解决实际问题。即把程序设计作为工具,描述解决实际问题的步骤,由计算机帮助我们解决问题。在完成此次课程设计的过程中,我学会了设置变量时命名规范且容易识别。在编写程序时,我做到了每个函数都有注释来说明功能,对参数和返回值也以注释的形式说明用途,关键的语句加入了注释解释,所以我学会了善于利用注释,增强程序的可读性。为了更好的实现用户交互,为了不使输入回车后还未观察数据就返回菜单,我使用了getchar()来吸收回车。在对文件进行读写的操作中,之前也遇到过乱码的问题,不过当时的解决办法都是退而求其次,将汉字信息写成英文字符,一直不知道乱码的症结所在,这次的课设,通过查阅资料找到了问题所在在于文件编码方式与编译器的不符,修改后问题得到解决。但由于时间关系,还有些许想法未能添加在程序中,如:按考勤日期对数据进行排序等。待时间充裕时,定要上手实现此功能,更好的充实程序设计。