这是第一次写的博客,想着用博客来记录下自己码代码的历程,如果有什么不好的地方欢迎各位指正
从2020.4.2到2020.4.23历时22天,算是把课设的内容完成了,后面还花费了一点时间增加了一点东西,算是给课设的一些加分项吧。加起来大概就是花费了一个月左右的时间完成这个课设。
因为课设的代码量较大,所以就将代码文件全部放到GitHub上面了,如果有需要的话可以戳这里
以下是正文内容。
学生证管理系统
问题描述:
简单来说就是,使用C语言对一些特定的数据(学生证信息)实现增删改查+统计的功能。
在编写代码之前,为了使逻辑思路不那么混乱,所以先使用process画好了大概的流程图,如下:
接下来为了编写使修改代码的便捷性,选择了之前未曾试过的分开一个个文件编写代码,再用一个头文件将不同文件的代码结合起来。参考了这篇博客,学会了怎么使用自定义头文件。
在设计的时候考虑到我们的学生号中已经包含了班级等信息,所以为了代码实现的便捷和查找的方便,使用了数组+双链表的数据结构,数据结构的图如下:
struct CLASS //定义班级结构体//
{
struct STUDENT *tail; //指向班级最后一个学生//
struct STUDENT *head; //指向班级第一个学生//
int num; //存储班级人数//
};
struct STUDENT //定义学生数据结构体//
{
struct STUDENT *last; //指向下一个学生指针//
char name[20]; //学生姓名//
char sex[10]; //学生性别//
char faculty[50]; //学生学院//
char major[50]; //学生专业//
char identity[20]; //学生身份//
char ID[20]; //学生学号//
char card_number[20]; //学生证卡号///
char expiration_date[20];//学生证有效日期//
struct STUDENT *next; //指向下一个学生指针//
};
相关代码文件:getin.c,close_down.c,start_up.c
整体的页面采用了上半部分为程序的主要内容,下面留下了3行的空间作为输入指令和提示的空间使用函数print_head()打印整个程序的框架。
//****************************************************************//
//调用此函数,则可以清空屏幕,并打印出程序边框,最后光标在(24,9)//
//****************************************************************//
//边框四角: (24,6),(86,6),(24,28),(86,28)//
//上下中点纵坐标标:18//
//左右中点横坐标:55//
#include"function.h"
void print_head()
{
int i;
system("cls");
gotoxy(24,6);
for(i=0; i<16; i++) //设置上边框//
{
printf("——");
}
gotoxy(47,7);
printf("|学生证管理程序|\n"); //程序名字//
gotoxy(47,8);
printf("————————\n"); //程序名字下划线//
gotoxy(24,28);
for(i=0; i<16; i++) //设置下边框//
{
printf("——");
}
for(i=6; i<=28; i++) //设置左右边框//
{
gotoxy(23,i);
printf("|");
gotoxy(86,i);
printf("|");
}
gotoxy(24,24); //设置提示栏//
for(i=24; i<=84; i++)
{
printf("-");
}
gotoxy(24,9); //跳转光标//
}
基本功能的实现都是比较基本的内容,没有太多可讲道的地方,可以选择直接跳过
相关代码文件:enter.c,getin.c
主要的思路:将信息依次录入到一个临时变量中,在输入完之后用户再输入确定的指令,然后将临时变量传入到输入数据到存储的结构体中的函数中,完成输入。
相关代码文件:del.c,ask_id.c
主要思路:先询问用户需要删除的学号,在用户输入正确的学号之后将该学号的信息打印出来,询问用户是否为该学号,之后用户选择确定之后成功删除。
相关代码文件:相关代码:show_class
主要思路:询问班级号,再将班级中的学生信息打印出来,由于使用了双向链表的结构来连接学生的信息,所以用户可以通过按‘←’和‘→’,来浏览学生的信息。
这部分代码感觉挺有意思的,贴在下面。
if(clarr[n].head==NULL) //若该班级头指针为空//
{
print_head();
gotoxy(42,12);
printf("|显示失败,并没有学生在%d班|",n);
clean_tip();
return go_back(); //询问用户下一步操作//
}
else
{
p1=clarr[n].head; //p1指向班级首名学生//
while(1)
{
print_student(*p1); //打印学生信息//
gotoxy(24,25);
printf("显示成功,%d班信息如上,按←和→进行浏览。",n); //提示栏语句//
err=getset();
gotoxy(24,26);
printf("按0退出程序,1返回主菜单。");
while(1)
{
key_down=getch(); //键盘输入,使程序继续显示下一名学生//
if(key_down==-32) //用于消除getch读取方向键时第一次返回的值,该死,不不知道为什么是-32//
{
continue;
}
if(key_down==75)
{
if(p1->last!=NULL)
{
p1=p1->last;
clean_tip(); //清除提示栏//
break;
}
else
{
gotoxy(24,27);
printf("已是第一位学生");
}
}
else if(key_down==77)
{
if(p1->next!=NULL)
{
p1=p1->next;
clean_tip(); //清除提示栏//
break;
}
else
{
gotoxy(24,27);
printf("已是最后一位学生");
}
}
else if(key_down=='0')
{
return 0;
}
else if(key_down=='1')
{
return 1;
}
else
{
error(err);
}
}
}
}
相关代码文件:show_student.c,print_student.c
主要思路:询问用户学号,若存在学号则直接打印学生信息,否则用户可以选择返回主菜单重新查询。
相关代码文件:modify.c,modify_op.c
主要思路:询问学号→打印信息→选择修改项→输入修改内容→打印修改后信息→选择返回或继续修改。
相关代码文件:statistics.c,sta_*,print_sex_table,
这部分功能可以选择统计班级人数,总人数,班级性别比例,总性别比例四项。
主要思路:
班级人数在班级结构体中已经进行了存储,所以统计时直接输出就可以
总人数就是对班级人数遍历一遍然后进行统计。
性别比例则是通过对班级中的学生性别进行一遍遍历然后进行统计。由于输入的不确定,所以将性别设置为了3个种类:男(boy),女(girl),其他
这部分包括用来处理程序中一些可能出现的细节问题,以及为了方便程序设计而使用的一些函数。
相关代码文件:gotoxy.c、getset.c
gotoxy(int x,int y):这个函数可以使当前光标移动到坐标(x,y)上
POINT getset():这个函数通过返回POINT的值获得当前光标的位置。
两个函数组合起来就可以很方便的对整个程序的框架进行设计。
参考博文:戳这里
相关代码文件:super_scan、super_int_scan
可以看到如果直接使用scanf输入姓名字符串时,如果用户不输入字符,
直接点击回车,光标此时会跳出程序外面,造成‘穿模’,但是在使用了输入函数之后:
如果直接输入回车,则会在提示栏中提示“输入不能为空”。
代码如下:
第一个用来输入字符以及字符串都可以。
//可以检测输入是否为空,并且没有多余的回车,将输入的整型存在上个函数传递进来的地址中//
#include "function.h"
int super_scan(char temp[])
{
char t;
int i=0;
POINT p;
p=getset();
while(1)
{
if((t=getchar())==EOF)
{
return 0;
}
if(t=='\n'&&i==0)
{
gotoxy(24,26);
printf("输入不能为空");
gotoxy(p.x,p.y);
}
else if(t=='\n')
{
break;
}
else
{
temp[i++]=t;
}
}
return 1;
}
第二个用来输入整型
//可以检测输入是否为空,并且没有多余的回车,将输入的整型存在上个函数传递进来的地址中//
#include "function.h"
int super_int_scan(int *n)
{
char t;
int i=1;
char a[50]={0};
POINT p;
a[0]='*';
p=getset();
while(1)
{
if((t=getchar())==EOF)
{
return 0;
}
if(t=='\n'&&i==1)
{
gotoxy(24,26);
gotoxy(p.x,p.y);
}
else if(t=='\n')
{
break;
}
else
{
a[i++]=t;
}
}
*n=transf(a);
return 1;
}
相关代码文件:go_back.c
相关代码文件:error.c
//该函数用于处理非法输入情况//
#include"function.h"
#pragma comment(lib,"Winmmlib")
void error(POINT point)
{
PlaySound(TEXT("err.wav"),NULL,SND_FILENAME | SND_ASYNC);
gotoxy(49,27);
printf("输入错误,请重试"); //提示栏提示//
gotoxy(point.x,point.y);
printf(" "); //消除上次输入内容//
gotoxy(point.x,point.y);
}
相关代码文件:success.c
int success()
{
print_head();
gotoxy(50,15);
printf("—————");
gotoxy(50,16);
printf("|操作成功!|");
gotoxy(50,17);
printf("—————");
return go_back();
}
//调用此函数从学号中提取班级整形编码//
//调用此函数也可将文件中班级编码字符串转换为整型//
//调用此函数还可以提取班级总人数//
#include"function.h"
#include
int transf(char *a)
{
int i,sum=0,len,j,mul;
if(a[0]=='*') //判断为班级编号标识符//
{
len=strlen(a);
for(i=1;i<len;i++) //将字符串转换为整型并返回//
{
for(j=len-i,mul=1;j>1;j--)
{
mul*=10;
}
sum+=(a[i]-48)*mul;
}
}
else if(a[0]=='&') //判断为班级人数标识符//
{
len=strlen(a);
for(i=1;i<len;i++) //将字符串转换为整型并返回//
{
for(j=len-i,mul=1;j>1;j--)
{
mul*=10;
}
sum+=(a[i]-48)*mul;
}
}
else //判读为学号//
{
for(i=7;i<10;i++) //对学号的去间进行转换//
{
if(i==7)
{
sum+=(a[i]-48)*100;
}
else if(i==8)
{
sum+=(a[i]-48)*10;
}
else if(i==9)
{
sum+=(a[i]-48)*1;
}
}
}
if(sum>0&&sum<10000) //班级编码只在1~9999之间,所以只返回这个区间的值//
{
return sum;
}
else //其他的则返回0//
{
return 0;
}
}
添加音效主要使用PlaySound语句。
PlaySound(TEXT("welcome.wav"),NULL,SND_FILENAME | SND_ASYNC );
详情使用方法参考这里
相关代码文件:welcom.c、outsys.c
实现效果:
底部的方块是加载条,以90ms一格的速度加载,配合着打开的音效刚好在音效播放完时加载完毕。
退出界面小人的手会以200ms/帧的速率进行摆动。
实现方法:主要用到了循环和sleep()函数,控制程序运行的速度,这样就能形成加载和运动的感觉。
以下是加载界面代码:
#include "function.h"
#pragma comment(lib,"Winmmlib")
void welcome()
{
int x,y,i;
PlaySound(TEXT("welcome.wav"),NULL,SND_FILENAME | SND_ASYNC );
print_head();
x=46;
y=8;
gotoxy(x,++y);
printf(" ■■■■■■■ ");gotoxy(x,++y);
printf(" ■ ■ ");gotoxy(x,++y);
printf("■ ■ ");gotoxy(x,++y);
printf("■ ■ ■ ■ ");gotoxy(x,++y);
printf("■ ■■ ■■ ■ ");gotoxy(x,++y);
printf("■ ■ ");gotoxy(x,++y);
printf("■ ■ ■ ■ ");gotoxy(x,++y);
printf(" ■ ■■■ ■ ■■ ");gotoxy(x,++y);
printf(" ■ ■ ■##■ ");gotoxy(x,++y);
printf(" ■■■■■■ ■■ ");gotoxy(x,++y);
printf(" ■■■ ■ ");gotoxy(x,++y);
printf("■■■■■■■■■■ ");gotoxy(x,++y);
printf(" ■■■ ");gotoxy(x,++y);
printf(" 欢迎使用本程序 ");
gotoxy(24,25);
printf("加载中");
gotoxy(24,27);
for(i=24;i<55;i++)
{
printf("■");
Sleep(90);
}
gotoxy(24,25);
printf("加载完毕,按任意建进入程序");
getch();
gotoxy(30,30);
}
以下是退出动画代码:
#include"function.h"
#pragma comment(lib,"Winmmlib")
void outsys()
{
PlaySound(TEXT("close.wav"),NULL,SND_FILENAME | SND_ASYNC );
int x,y,i;
print_head();
x=46;
y=8;
gotoxy(x,++y);
printf(" ■■■■■■■ ");gotoxy(x,++y);Sleep(80);
printf(" ■ ■ ");gotoxy(x,++y);Sleep(80);
printf("■ ■ ");gotoxy(x,++y);Sleep(80);
printf("■ ■ ■ ■ ");gotoxy(x,++y);Sleep(80);
printf("■ ■■ ■■ ■ ");gotoxy(x,++y);Sleep(80);
printf("■ ■ ");gotoxy(x,++y);Sleep(80);
printf("■ ■ ■ ■ ");gotoxy(x,++y);Sleep(80);
printf(" ■ ■■■ ■ ");gotoxy(x,++y);Sleep(80);
printf(" ■ ■ ");gotoxy(x,++y);Sleep(80);
printf(" ■■■■■■ ");gotoxy(x,++y);Sleep(80);
printf(" ■■■ ");gotoxy(x,++y);Sleep(80);
printf("■■■■■■■■■ ");gotoxy(x,++y);Sleep(80);
printf(" ■■■ ");gotoxy(x,++y);Sleep(80);
printf(" 感谢使用本程序 ");
gotoxy(24,25);
printf("已成功退出,按任意键继续");
i=1;
while(!_kbhit())
{
i++;
x=64;y=15;
gotoxy(x,++y);
printf(" ■■");gotoxy(x,++y);
printf(" ■##■");gotoxy(x,++y);
printf(" ■■");gotoxy(x,++y);
printf(" ■");gotoxy(x,++y);
printf("■");gotoxy(x,++y);
Sleep(200);
x=64;y=15;
gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
x=64;y=17;
gotoxy(x,++y);
printf(" ■■");gotoxy(x,++y);
printf("■■■##■");gotoxy(x,++y);
printf(" ■■");gotoxy(x,++y);
Sleep(200);
x=64;y=17;
gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
printf(" ");gotoxy(x,++y);
if(i==100)
{
break;
}
}
x=64;y=17;
gotoxy(x,++y);
printf(" ■■");gotoxy(x,++y);
printf("■■■##■");gotoxy(x,++y);
printf(" ■■");gotoxy(x,++y);
getch();
gotoxy(30,30);
}
本次课设的思路和代码基本介绍完成,如果有任何修改意见或问题欢迎各位提出。
这也是本人第一次第一次写博客,以后会继续更新的,撒花花❀❀