zoukankan      html  css  js  c++  java
  • 华南农业大学-高级语言程序设计-学生证管理系统

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

    从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("|学生证管理程序|
    ");         //程序名字//
        gotoxy(47,8);
        printf("————————
    ");                 //程序名字下划线//
    
        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=='
    '&&i==0)
            {
                gotoxy(24,26);
                printf("输入不能为空");
                gotoxy(p.x,p.y);
            }
            else if(t=='
    ')
            {
               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=='
    '&&i==1)
            {
                gotoxy(24,26);
                gotoxy(p.x,p.y);
            }
            else if(t=='
    ')
            {
               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);
    
    }
    



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

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

    ``

  • 相关阅读:
    CF1324F Maximum White Subtree
    CF1204C Anna, Svyatoslav and Maps
    CF1187E Tree Painting
    CF1304E 1-Trees and Queries
    深入探究jvm之类装载器
    深入探究jvm之GC的算法及种类
    深入探究jvm之GC的参数调优
    spring源码解析之AOP原理
    spring注解扫描组件注册
    cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题
  • 原文地址:https://www.cnblogs.com/kstar/p/13089337.html
Copyright © 2011-2022 走看看