C语言程序设计——学生信息考勤系统

 

1.课程设计目的

C语言课程设计是计算机科学与技术专业重要的实践性教学环节之一,本次设计结合实际应用的要求,使课程设计既覆盖C语言程序设计的知识点,又接近工程实际需要。本次设计的目的是通过课程设计的综合训练,培养学生实际分析问题、解决问题的能力,以及编程和动手能力,最终目标是通过课程设计这种形式,帮助学生系统掌握C语言程序设计这门课程的主要内容,养成良好的编程习惯,更好的完成教学任务。

2.课程设计要求与任务:

2.1整体要求:

本次课程设计利用《C语言程序设计》课程中所学到的编程知识和编程技巧,完成具有一定难度和工作量的程序设计题目,帮助学生掌握编程、调试的基本技能,独立完成所布置的任务。

2.2系统要求:

1、对系统进行功能需求分析

2、设计合理的数据结构和系统框架

3、编程简练,程序功能齐全,能正确运行

4、说明书、流程图要清楚

5、课题完成后必须按要求提交课程设计报告

2.3设计任务:

考勤系统设计:设计一考勤系统,考勤信息记录学生的缺课情况

存储信息:缺课日期、第几节课、课程名称、学生姓名、学生学号、缺课类型(迟到、早退、请假及旷课)。

系统具有以下功能:

1.录入学生的缺课记录;

2.修改某个学生的缺课记录;

3.查询某个学生的缺课情况;

4.统计某段时间内,旷课学生姓名及旷课次数,按旷课次数由多到少排序;

5.统计某段时间内,有学生旷课的课程及旷课人次,按旷课人次由多到少排序;

6.系统以菜单方式工作。

2.4开发环境与工具:

VC 6.0(编程环境)、Microsoft Visio(建模绘图)、Microsoft Word(文档撰写)。

2.5设计说明目录:

  1. 简单的需求说明;
  2. 概要设计;
  3. 各模块的详细设计(程序流程图);
  4. 各模块源代码;
  5. 运行结果;
  6. 验收报告。

 
  1. 课程设计说明书

3.1需求分析

1.主函数编译菜单函数,菜单函数调用自定义choose函数采用switch实现菜单功能的选择;
2.使用自定义函数void data_print()将学生缺勤数据输入到自定义的文件中(信息包括:缺课日期、第几节课、课程名称、学生姓名、学生学号、缺课类型);
3.使用自定义函数void data_modify()对已有文件中学生缺勤记录进行修改;
4.使用自定义函数void data_search()查询某个学生的缺课情况;(可按学号,姓名查找);
5.使用自定义函数void stud_arrange()统计某段时间内,旷课学生姓名及旷课次数(以学生为统计的第一要素),按旷课次数由多到少排序;
6.使用自定义函数void subj_arrange()统计某段时间内,有学生旷课的课程及旷课人次(以课程为统计第一要素),按旷课人次由多到少排序;

3.2概要设计     

      

3.3详细设计

  1. 初始化定义结构体

struct student

{

       char date[20];

       int time;

       char subject[20];

       char name[20];

       long int number;

       char type[20];

};//设一个包含学生基本信息的结构体

typedef struct

//typedef的新类型名取代(SM—>Student)方便下面的识别与理解

{

       int length;

       struct student kq[30];

}SM;

//设二重结构体包含第一层结构体,对它的成员数进行赋值与计数

  1. 菜单展示及功能选择模块

int main()

{

       void menu();

       char choose[10];

       menu();

       printf("\n是否返回主页面?\nYes!orNo!(输入其他退出系统)\n\n请选择:");

       scanf("%s",choose);

       if(strcmp(choose,"Yes")==0||strcmp(choose,"yes")==0)

          menu();

       else

          printf("谢谢使用!");

       return 0;

}

void menu()

{

       system("cls");

       void choose();

    printf("                                           ◆欢迎进入学生信息考勤系统◆\n");

    printf("                                             1.录入学生缺课记录\n");

    printf("                                             2.修改学生的缺课记录\n");

    printf("                                             3.查询学生的缺课记录\n");

    printf("                                             4.在规定时间段内,学生旷课次数的整理与排序\n");

    printf("                                             5.在规定时间段内,课程中学生缺勤数量的整理与排序\n");

    printf("                                             6.退出系统\n\n");

   printf("请选择想要使用功能对应的序号:");

   choose();

}

void choose()

//主要程序通过此函数的switch语句进行选择执行,同时为异常处理提供可能

{

       void data_print();

       void data_modify();

       void data_search();

       void stud_arrange();

       void subj_arrange();

       //声明每个功能对应的函数

\* MERGEFORMAT

       void read();

    read();

       int x;

    scanf("%d",&x);

       switch(x)

    {

          case 1:data_print();break;

          case 2:data_modify();break;

          case 3:data_search();break;

          case 4:stud_arrange();break;

          case 5:subj_arrange();break;

          case 6:printf("\n");break;

          default:printf("错误!请重新选择应用:");choose();

          //default的作用是对于输出范围外编号时,

通过递归函数重新选择功能

       }

}

  1. 读入文档信息模块

void read()// 负责实现将基础文件的信息读入结构体的功能

{

       int n,i;

       FILE *fp;

       if((fp=fopen("file.doc","r"))==NULL)

       {

              printf("cannot open the file!");

              exit(0);

       }

       fscanf(fp,"%d\n",&Student.length);//利用fscanf将文件信息读入结构体

       for(i=0;i<Student.length;i++)

          {

              fscanf(fp,"\n%s\t%d\t%s\t%s\t%ld\t%s",

                 Student.kq[i].date,&Student.kq[i].time,

                 Student.kq[i].subject,Student.kq[i].name,

                 &Student.kq[i].number,Student.kq[i].type);

          }

       fclose(fp);

}

//先新建一个文件存放已有学生缺课记录,用read函数在主函数中事先读取信息,为下面的功能实现打下基础

  1. 录入学生缺课记录模块

void data_print()

//负责实现在文件中录入新增学生缺课记录的函数

 {

   system("cls");

\* MERGEFORMAT

      int n,i;

       FILE *fp;

       if((fp=fopen("file.doc","w"))==NULL)

       {

              printf("cannot open the file!");

              exit(0);

       }

       printf("请输入准备录入缺课学生的数量:");

       scanf("%d",&n);

       printf("请分别输入以下信息\n缺课日期\t第几节课\t课程名称\t学生姓名\t学生学号\t缺课类型\n");

       for(i=Student.length;i<n+Student.length;i++)

       //i=Student.length旨在在已有记录后输入新的缺课记录进入结构体

          scanf("%s%d%s%s%ld%s",

          Student.kq[i].date,&Student.kq[i].time,

          Student.kq[i].subject,Student.kq[i].name,

          &Student.kq[i].number,Student.kq[i].type);

       Student.length=Student.length+n; 

       fprintf(fp,"%d\n",Student.length);//首先在文件顶端输入记录个数

       printf("录入文件的缺课记录如下:\n");

       for(i=0;i<Student.length;i++)

       {

              fprintf(fp,"%s\t%d\t%s\t%s\t%ld\t%s\n",

              Student.kq[i].date,Student.kq[i].time,

              Student.kq[i].subject,Student.kq[i].name,

              Student.kq[i].number,Student.kq[i].type);

              //利用fprintf将结构体中的数据信息录入到文件中

              printf("\n%s\t%d\t%s\t%s\t%ld\t%s\n",

              Student.kq[i].date,Student.kq[i].time,

              Student.kq[i].subject,Student.kq[i].name,

              Student.kq[i].number,Student.kq[i].type);

              printf("--------------------------------\n");

              //检测printf,检验信息是否正常录入文件,可删除

       }

       printf("\n学生缺课信息已成功录入文件file.doc中,请查看!\n");

       fclose(fp);

 }

  1. 修改学生缺课信息模块

void data_modify()//负责实现在文件中局部修改全局输出学生缺课记录的函数

{

       system("cls");

       void md_part();

       void data_print();

       int n,i,number,choice,book=0;

       char name[20];

       FILE *fp;

       if((fp=fopen("file.doc","w"))==NULL)

\* MERGEFORMAT

       {

              printf("cannot open the file!");

              exit(0);

       }

       printf("请选择查找方式!\n姓名搜索输入1。学号搜索输入2。输入其他默认选择1。\n\n您的选择是:"); //选择查找方式

       scanf("%d",&choice);

         if(choice!=2)

         {

            printf("请输入准备修改学生的姓名 :");

            scanf("%s",name);

            printf("记录序号  缺课日期  第几节课  课程名称  学生姓名  学生学号  缺课类型\n");

            for(i=0;i<Student.length;i++)

             {

               if(strcmp(name,Student.kq[i].name)==0)

                {

                  printf("    %d     %s\t%d\t%s\t  %s\t    %ld\t%s\n",

                        i,Student.kq[i].date,Student.kq[i].time,

                  Student.kq[i].subject,Student.kq[i].name,

                  Student.kq[i].number,Student.kq[i].type);

                  printf("--------------------------------\n");

                  book++;

                }

             }

      }

         else

         {

           printf("请输入准备修改学生的学号 :");

           scanf("%d",&number);

           printf("记录序号  缺课日期  第几节课  课程名称  学生姓名  学生学号  缺课类型\n");

            for(i=0;i<Student.length;i++)

             {

               if(number==Student.kq[i].number)

                {

                  printf("    %d     %s\t%d\t%s\t  %s\t    %ld\t%s\n",

                        i,Student.kq[i].date,Student.kq[i].time,

                  Student.kq[i].subject,Student.kq[i].name,

                  Student.kq[i].number,Student.kq[i].type);

                  printf("--------------------------------\n");

                  book++;

                }

            }

      }

    if(book)

    {

          md_part();

          fprintf(fp,"%d\n",Student.length);

          for(i=0;i<Student.length;i++)

           {

                 fprintf(fp,"%s\t%d\t%s\t%s\t%ld\t%s\n",

                 Student.kq[i].date,Student.kq[i].time,

                 Student.kq[i].subject,Student.kq[i].name,

                 Student.kq[i].number,Student.kq[i].type);

           }

           printf("\n修改后的学生缺课信息已成功录入文件file.doc中,请查看!\n");

       }

       else

       {

              printf("没有您想要修改的学生记录!\n");

              printf("您可以选择以下功能:1.重新输入 2.录入新记录 3.放弃修改\n(选择其他则默认放弃修改)\n\n您的选择是:");

              scanf("%d",&choice);

              switch(choice)

              {

                     case 1:data_modify();break;

                     case 2:data_print();break;

                     default:printf("功能结束\n");break;

              }

       }

       fclose(fp);    

}

void md_part()

//数据修改函数另辟一个小修改函数,用来实现对同一对象的多条数据的多个修改

{

       int i,answer;

       printf("是否继续进行修改?\n是,请输入1。否,请输入0。\n\n您的选择是:");

       scanf("%d",&answer);

       if(answer)

       {

           printf("请选择其中一条记录序号,进行信息修改:");

           scanf("%d",&i);

           printf("请输入该记录修改后的各项信息:\n");

           scanf("%s%d%s%s%ld%s",

             Student.kq[i].date,&Student.kq[i].time,

             Student.kq[i].subject,Student.kq[i].name,

             &Student.kq[i].number,Student.kq[i].type);

           printf("是否继续进行修改?\n是,请输入1。否,请输入0。\n您的选择是:");

           scanf("%d",&answer);

           if(answer)

              md_part();

           else

              printf("修改结束!");

    }

    else

     printf("修改结束!");

}

  1. 搜索学生缺课记录模块

 void data_search()//负责实现在文件中搜索学生缺课记录并录入另一指定文件的函数

 {

    system("cls");

       FILE *out;

       int i,book=0,choice,number;

       char outfile[20],name[20];//name数组用于对学生姓名的输入

       printf("请输出放置搜索结果的文件名:");

       scanf("%s",outfile);

       if((out=fopen(outfile,"w"))==NULL)

       {

              printf("cannot open the file!\n");

              exit(0);

       }

       printf("请选择查找方式!\n姓名搜索输入1。学号搜索输入2。输入其他默认选择1。\n\n您的选择是:"); //选择查找方式

       scanf("%d",&choice);

\* MERGEFORMAT

       if(choice!=2)

       {

         printf("请输入想要查询学生的姓名:");

         scanf("%s",name);

         for(i=0;i<Student.length;i++)

        {

                 if(strcmp(name,Student.kq[i].name)==0)

//利用strcmp函数实现对姓名的对比及录入文件

                   {

                         fprintf(out,"%s\t%d\t%s\t%s\t%ld\t%s\n",

                         Student.kq[i].date,Student.kq[i].time,

                         Student.kq[i].subject,Student.kq[i].name,

                         Student.kq[i].number,Student.kq[i].type);

                         book=1;

//book用于标记是否搜索到相关记录

                         printf("\n%s\t%d\t%s\t%s\t%ld\t%s\n",

                         Student.kq[i].date,Student.kq[i].time,

                         Student.kq[i].subject,Student.kq[i].name,

                         Student.kq[i].number,Student.kq[i].type);

                         printf("--------------------------------\n");

                   }

           }

       }

       else

       {

         printf("请输入想要查询学生的学号:");

         scanf("%d",&number);

         for(i=0;i<Student.length;i++)

        {

                 if(number==Student.kq[i].number)

                   {

                         fprintf(out,"%s\t%d\t%s\t%s\t%ld\t%s\n",

                         Student.kq[i].date,Student.kq[i].time,

                         Student.kq[i].subject,Student.kq[i].name,

                         Student.kq[i].number,Student.kq[i].type);

                         book=1;

                         printf("\n%s\t%d\t%s\t%s\t%ld\t%s\n",

                         Student.kq[i].date,Student.kq[i].time,

                         Student.kq[i].subject,Student.kq[i].name,

                         Student.kq[i].number,Student.kq[i].type);

                         printf("--------------------------------\n");

                   }

           }

       }

       fclose(out);

       if(book)

         printf("\n搜索结果已经录入文件%s中,请查看!\n",outfile);

       else

         printf("\n此同学无缺课记录!\n");

}

  1. 统计整理学生旷课次数模块

struct s1

{

       char name[20];

       int time;

 } stud[30]={0};

 //创建一个包含学生姓名及其缺课次数(time)的结构体

void stud_arrange()

//负责实现在文件中搜索某一时间段学生缺课次数并将其排序后录入另一指定文件中的函数

{

   system("cls");

       FILE *fp;

       char filename[20];

       int time1,time2,i,j,k,t,n=0,book=0,choice;//i,j,t,n用于下面的循环计数,book作为判别标记

       struct s1 max;//定义s1结构体变量,用作排序交换时的临时变量

       printf("请输入要放置学生缺勤记录整理结果的文件名:");

       scanf("%s",filename); //另外新建一个文件,用来存放筛选的结果

       if((fp=fopen(filename,"w"))==NULL)

       {

              printf("cannot open the file!");

              exit(0);

       }

       printf("一天的总课节数为10节\n\n");

       printf("请输入以两课节为始末的时间段:");

       scanf("%d%d",&time1,&time2);

       //以时间段为第一筛选标准,设两个存放数字的变量来表示一时间段

       for(i=0;i<Student.length;i++)

       {

         book=0;

         if(time1<=Student.kq[i].time&&Student.kq[i].time<=time2)

         //对已经录入双重结构体的信息中的课节数根据时间进行判断

         //判断符合缺课时间段的学生姓名及次数录入s1(stud)结构体

\* MERGEFORMAT

           {

              for(t=0;t<n+1;t++)//判断符合缺课时间段的学生姓名是否已录入一次

                   {

                       if(strcmp(stud[t].name,Student.kq[i].name)==0)

                       {

                              book=1;

                         k=t;

                       }

                   }

              //book标记,姓名已有加缺课次数(stud.time),无则录姓名加次数

                 if(book)

                    {

                         if(strcmp(Student.kq[i].type,"旷课")==0)

                        stud[k].time++;

                    }

                 else

                    {

                        strcpy(stud[n].name,Student.kq[i].name);

                        //利用strcpy字符串函数将符合条件的学生姓名复制到s1结构体中

                        if(strcmp(Student.kq[i].type,"旷课")==0)

                        stud[n].time++;

                            //赋名的第一次不忘判断其是否旷课,其为s1结构体的第n个成员,借此叠加次数

                        n++;

                    }

           }

       }

       if(n)

       {

         for(i=0;i<n-1;i++)

           {

                 t=i;

                 for(j=i+1;j<n;j++)

                    if(stud[t].time<stud[j].time)

                         t=j;

                 max=stud[t];

                stud[t]=stud[i];

                 stud[i]=max;

                 //将一个成员的信息通过中间结构体变量max全部转移

           }

         fprintf(fp,"缺勤学生姓名  旷课次数\n");//先填写整理后结果的条数

         printf("缺勤学生姓名  旷课次数\n");

         for(i=0;i<n;i++)

           {

                  fprintf(fp,"%s\t\t\t%d次\n",stud[i].name,stud[i].time);

                  printf("%s\t\t%d次\n",stud[i].name,stud[i].time);

                  printf("--------------------------------\n");

           }

          printf("\n统计排序后的结果已经录入文件%s中,请查看!\n",filename);

    }

    else

    {

          printf("此时间段无学生存在缺勤记录!\n");

          printf("输入1重选时间段。输入0退出使用。\n\n请选择接下来的操作:");

              scanf("%d",&choice);

              if(choice)

                stud_arrange();

              else

                printf("功能结束!");

       }

         fclose(fp);

}

  1. 统计整理课程旷课学生人数模块

 struct s2

{

       char subject[20];

       int num;

 } subj[30]={0};

 //创建一个包含课程名称及缺勤人数(num)的结构体

void subj_arrange()

//负责实现在文件中搜索某一时间段内课上缺勤学生人数并将其排序后录入另一指定文件中的函数

{

    system("cls");

       FILE *fp;

       char filename[20];

       int time1,time2,i,j,k,t,n=0,book=0,choice;//i,j,t,n用于下面的循环计数,book作为判别标记

       struct s2 max;

       printf("请输入要放置课程中学生缺勤人数整理结果的文件名:");

       scanf("%s",filename); //另外新建一个文件,用来存放筛选的结果

       if((fp=fopen(filename,"w"))==NULL)

       {

\* MERGEFORMAT

              printf("cannot open the file!");

              exit(0);

       }

       printf("一天的总课节数为10节\n\n");

       printf("请输入以两课节为始末的时间段:");

       scanf("%d%d",&time1,&time2);

       //以时间段为第一筛选标准,设两个存放数字的变量来表示一时间段

       for(i=0;i<Student.length;i++)

       {

         book=0;

         if(time1<=Student.kq[i].time&&Student.kq[i].time<=time2)

         //对已经录入双重结构体的信息中的课节数字根据时间段进行判别

         //判断符合缺课时间段的课程名称及缺勤人数录入s2(subj)结构体

           {

              for(t=0;t<n+1;t++)

            //判断符合规定时间段的课程名称是否已录入

               {

                     if(strcmp(subj[t].subject,Student.kq[i].subject)==0)

                     {

                            book=1;

                            k=t;

                       }

                 }

              //book标记,课程名称已有加人数,没有再赋课程名称加人数

                 if(book)

                  {

                       if(strcmp(Student.kq[i].type,"旷课")==0)

                      subj[k].num++;

                  }

                 else

                    {

                         strcpy(subj[n].subject,Student.kq[i].subject);

                         if(strcmp(Student.kq[i].type,"旷课")==0)

                              subj[n].num++;

                         n++;

                    }

           }

       }

       if(n)

       {

         for(i=0;i<n-1;i++)

          {

                t=i;

                for(j=i+1;j<n;j++)

                    if(subj[t].num<subj[j].num)

                         t=j;

                max=subj[t];

                subj[t]=subj[i];

                subj[i]=max;

                //将一个成员的信息通过中间结构体变量max全部转移

          }

         fprintf(fp,"课程名称  缺勤人数\n");

         printf("课程名称  缺勤人数\n");//先填写整理后结果的条数

         for(i=0;i<n;i++)

           {

                 fprintf(fp,"%s\t\t\t%d名\n",subj[i].subject,subj[i].num);

               printf("%s\t\t%d名\n",subj[i].subject,subj[i].num);

                 printf("--------------------------------\n");

           }

         printf("\n统计排序后的结果已经录入文件%s中,请查看!\n",filename);

    }

    else

    {

          printf("此时间段无课程有学生缺勤!\n");

          printf("输入1重选时间段。输入0退出使用。\n\n请选择接下来的操作:");

              scanf("%d",&choice);

              if(choice)

                subj_arrange();

              else

                printf(功能结束!");

       }

       fclose(fp);

}

4.课程设计成果

4.1菜单模块

使用主函数包含菜单函数,菜单函数包含功能选择函数,最后让进行选择执行完一个功能后是否返回菜单页。选择函数使用switch语句,在序号对应的功能后加上函数及break,输入序号以运行对应函数。在此页面下的异常输入情况,再次使用choose函数,对再次输入选择序号操作即利用其递归。

4.2学生缺课记录录入模块

先输入录入缺课记录的条数,(对此的计数方便下面的循环比较功能)再依次对应提示语句输入相关学生缺课记录,将记录条数从已有的记录上进行叠加,最后将结构体中的所有缺课记录一并输出到控制台上,以展示给用户基础记录文件中的所有缺课记录。



4.3学生缺课记录修改


对于缺课记录,必须找到搜索需要修改的对象的缺课记录,我这边拥有姓名及学号两种搜索方法,选用if语句进行搜索方式的选择,以2与!2的选择以去除异常输入的情况。若无搜索结果,用户可选择(1.重新输入2.录入记录3.结束修改)三种操作,其中1,2操作均是对函数的再引用。若存在搜索记录,则按基本信息,逐行输出便于用户对记录的选择修改。修改后仍可选择,继续修改与结束修改,继续修改通过函数调用以实现修改多条记录的功能。

正常情况与异常处理:


 

  1. ]4B)BHI({_VM1TE_04%LM(X

    4学生缺课记录搜索模块

此功能拥有姓名及学号两种搜索方法,选用if语句进行搜索方式的选择,以2与!2的选择以去除异常输入的情况。若无搜索结果,则输出“此同学无缺课记录!”。

4.5时间段内,学生缺旷课次数模块

因为功能要求在一段时间内,所以我选择将课节作为时间参考标准,首先输入两课节,以作为一个时间段,再通过循环比较将课节数在此时间段内的同学名字录入新结构体中,对于旷课计数则进行

循环字符比较,是则加一。最后通过选择排序法,将学生的缺课次数进行次数由多到少的排序。若在该时间段内无学生缺勤,则进行选择,是否再选择时间段查找计数排序,还是结束使用。

正常情况异常处理与文件信息:


4.6统计某时间段内,课上旷课人数模块

因为功能要求在一段时间内,所以我选择将课节作为时间参考标准,首先输入两课节,以作为一个时间段,再通过循环比较将课节数在此时间段内的课程名称录入新结构体中,对于旷课人数则进行循环字符比较,是则加一,否不记。最后通过选择排序法,将课程上旷课人数进行由多到少的排序。若在该时间段内课上无学生缺勤,则进行选择,是否再选择时间段查找计数排序,还是结束使用。

正常情况与文件样貌:(异常处理跟上点相同,此处省略)

5.课程设计心得

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值