华南农业大学-高级语言程序设计-学生证管理系统

这是第一次写的博客,想着用博客来记录下自己码代码的历程,如果有什么不好的地方欢迎各位指正

从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();
}

数据类型转换函数

  • 在录入文本信息已经用户输入学号时,由于需要从学号中提取出班级编号进行‘分班’处理,所以使用了一个数据类型转换的函数进行处理。
  • 这函数有三个功能,1、从学号中提取出班级编号;2、将文本中的班级人数转换为整型;3、将文本中班级编号转换为整型。
//调用此函数从学号中提取班级整形编码//
//调用此函数也可将文件中班级编码字符串转换为整型//
//调用此函数还可以提取班级总人数//

#include"function.h"
#include <math.h>

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;
    }


}

有趣的额外功能

添加音效

  • 由于觉得这个程序做完之后还是太过单调,没有什么有趣的地方,用户使用起来可能会觉得很无聊,所以在一些操作上加入了按键的音效,比如删除成功的音效,菜单选择的音效,进出程序,退出程序等音效。为了使用户更有熟悉感,这些音效据采用了Windows的内置系统音效。

添加音效主要使用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);

}



本次课设的思路和代码基本介绍完成,如果有任何修改意见或问题欢迎各位提出。

这也是本人第一次第一次写博客,以后会继续更新的,撒花花❀❀

``

posted @ 2020-06-10 21:46  k_star  阅读(291)  评论(0编辑  收藏  举报