C语言项目:打卡机实例

    科技2022-07-31  122

    C语言项目:打卡机实例

    题干行文方式前言1.通读题干,提取主干2.定义结构,函数声明3.搭建框架,分级实现 思维导图代码笔者敬告

    题干

    应市场需求,某工程师现设计了一款新上下班打卡机,打卡机具有以下功能: (1) 上班打卡,员工具有编号(首位为 1 的六位编号),输入编号后,再 输入校验码,校验码生成规则:员工编号除首位反序,再与员工编号 求和,如:员工编号,110086,校验码为 178087。校验码错误即打 卡失败。记录打卡时间 (2) 下班打卡,只需输入员工编号即可。记录打卡时间,显示该人员今天 上班时长,如果上班时长不够,显示早退 xx 分钟。可以更新下班打 卡时间。无下班打卡显示缺卡。 (3) 可以设置规定上班时长,如 9 小时 (4) 测试需要可以规定 6 秒=实际 1 小时,每次测试,输入指令后,开启 打卡机,打卡机开启模拟时间为:周一早上七点。程序运行结束为周 五晚 12 点。 (5) 实行弹性打卡制,如前一天上班时长超过规定时长 3 小时以上,第 二天迟到 2 小时以内不算迟到。 (6) 打卡机运行结束之前,每周该打卡机会生成每周考勤周报,显示周平 均上班时长,周迟到,早退,缺卡次数等。 额外要求: 1、创建项目 2、合理定义所需函数 ①主函数中只允许有 clockin_machine_start()调用; ②每个函数不得超过50行; ③函数声明见名知意,单词之间用_隔开; ④变量名简短清晰 3、按照任务概述实现函数流程

    行文方式

    前言

    前人有言: 先搭框架,逐步扩充, 由简到繁,最后完善。 边编程,边调试,边扩充。

    自顶向下,逐步细化。

    1.通读题干,提取主干

    进行此项步骤。需要将项目的主干提取出来。类比于将句子的主谓宾提取出来。笔者采用填空题的做法。分部提取。此处建议按照如图所示方式归类。归类要求:无任何废话。 建议利用此图填空。若确有所需。可灵活变化(这里的任务是按照这张表想一想。有个大概的想法就行了)

    2.定义结构,函数声明

    对各个需要用到的类型进行定义。(至少包含两个变量。尽量精简) 对实现功能的函数进行声明。对可能需要反复用到的、实现代码量过长会导致一个函数超过50行的代码进行包装。 建议将具体结构放在备注中。方便阅读。

    3.搭建框架,分级实现

    准备工作做完。就去搭建框架。将逻辑用C语言表达出来。不妨将定义的结构。函数,从思维导图搬到代码中。初始定义为空。在主函数中空实现。

    #include<stdio.h> #include <memory.h> typedef struct { unsigned int hour; unsigned int min; unsigned int sec; unsigned int day; }my_time_t; typedef struct { unsigned char time_num;//工作时间 unsigned char work_state;//工作状态 my_time_t check_in;//上班打卡时间 my_time_t check_out;//下班打卡时间 unsigned char check_in_flag;//上班打卡标志 unsigned char check_out_flag;//下班打卡标志 }employee_work_info_t; typedef struct { int base;//员工号 employee_work_info_t work[5];//表示周一到周五的工作信息 }employee_info_t; //函数声明 unsigned char employee_check_num_check(int input_num, int check_num);//检查 void time_run(my_time_t* my_time);//模拟时间的流逝函数 int clockin_machine_start();//调用该函数,程序开始运行 void work_in_start(my_time_t*, employee_info_t*);//上班打卡 void work_out_end(my_time_t*, employee_info_t*);//下班打卡 void show_punch_menu(my_time_t*, employee_info_t*);//显示一周的打卡信息 unsigned char employee_check_num_check(int input_num, int check_num) { return 0; } void time_run(my_time_t* my_time) { } int clockin_machine_start() { return 0; } void work_in_start(my_time_t*, employee_info_t*) { } void work_out_end(my_time_t*, employee_info_t*) { } void show_punch_menu(my_time_t*, employee_info_t*) { } int main(int argc, int** argv) { employee_info_t employee_zhangsan; my_time_t my_time; int day_paper_flag = 0; char result = 0, input_flag = 0; memset(&employee_zhangsan, 0, sizeof(employee_info_t));//将张三的信息初始化为0 memset(&my_time, 0, sizeof(my_time));//将我的时间初始化为0 //monday 7:00 my_time.hour = 7; my_time.min = 0; my_time.sec = 0; my_time.day = 1; while (1) { time_run(&my_time);//时间开始流逝 /* 判断时间,周一到周五7点到9点可以进行上班打卡,在上班打过卡的情况下, 时间为16点到20点可以进行下班打卡,在周六展示员工一周的打卡情况; */ if (my_time.hour >= 7 && my_time.hour < 12)//时间7点到9点,可以上班打卡 { work_in_start(&my_time, &employee_zhangsan); } else if (my_time.hour >= 16 && my_time.hour < 20 && employee_zhangsan.work[my_time.day].check_in_flag) { work_out_end(&my_time, &employee_zhangsan); } show_punch_menu(&my_time, &employee_zhangsan); } return 0; } }

    需要能编译通过。但是无任何功能。 框架搭建完成。继续分级实现。何谓分级实现? 在实现功能时。需要考虑什么功能先实现,什么功能后实现的问题。 就拿写文章来说。我们需要一条线。能贯穿始终。各项工作都在这个线上进行。毫无疑问。对本文来说,时间流逝控制函数time_run()是需要首先实现的。它贯穿本文始终。有了它。主函数中的类容才得以完成。当文章有了线索。其中各项风景就可以由我们布置了!它们就是我们平时练习的函数功能实现。那是需要积累方法的部分。此处不涉及。

    思维导图

    代码

    能在VS2019中调试成功

    #include<conio.h> #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <math.h> #include <windows.h> //类型定义 typedef struct { unsigned int hour; unsigned int min; unsigned int sec; unsigned int day; }my_time_t; typedef struct { unsigned char time_num;//工作时间 unsigned char work_state;//工作状态 my_time_t check_in;//上班打卡时间 my_time_t check_out;//下班打卡时间 unsigned char check_in_flag;//上班打卡标志 unsigned char check_out_flag;//下班打卡标志 }employee_work_info_t; typedef struct { int base;//员工号 employee_work_info_t work[5];//表示周一到周五的工作信息 }employee_info_t; //函数声明 unsigned char employee_check_num_check(int input_num, int check_num);//检查 void time_run(my_time_t* my_time);//模拟时间的流逝函数 int clockin_machine_start();//调用该函数,程序开始运行 void work_in_start(my_time_t*, employee_info_t*);//上班打卡 void work_out_end(my_time_t*, employee_info_t*);//下班打卡 void show_punch_menu(my_time_t*, employee_info_t*);//显示一周的打卡信息 char employee_info_get(int* num)//从键盘非阻塞地获取字符,转化为int类型给num; { char temp = 0; static char num_string[6] = { 0 }; static unsigned char i = 0; temp = _kbhit(); if (0 != temp) { char ch = _getch(); if ('q' == ch) { return 2; } printf("\n%c\r", ch); if (i < 5) { num_string[i] = ch; i++; return 0; } else { printf("\n%c\r", ch); num_string[5] = ch; i = 0; //"123456" -> 123456 *num = atoi(num_string);//stdlib.h memset(num_string, 0, sizeof(num_string)); return 1; } } return 0; } void employee_check_num_get(int num, int* check_num) { int temp = num % 100000, num_ever = 0, new_num = 0; unsigned char i = 0; for (i = 0; i < 5; i++) { num_ever = (temp / (10000 / (int)(pow(10, i)))) % 10; new_num += num_ever * (int)(pow(10, i)); } new_num += num; *check_num = new_num; } unsigned char employee_check_num_check(int input_num, int check_num) { if (input_num == check_num) { return 1; } else { return 0; } } void work_in_start(my_time_t* my_time, employee_info_t* employee_zhangsan) { /* num为员工的编号,check_num为校验码,result为返回值,input__flag为输入的标记 */ int num = 0; static int check_num = 0; char result = 0; static char input_flag = 0; result = employee_info_get(&num);//员工信息获取,将返回值给result,2退出,1员工编号输入成功 if (2 == result) { printf("退出系统\r\n"); return; } else if (1 == result) { input_flag++; if (1 == input_flag) { printf("你输入的编号是[%d]\r\n", num); printf("张同学的num值%d\r\n", num); employee_zhangsan->base = num; employee_check_num_get(num, &check_num);//由编号num得到验证码check_num printf("请输入验证码[%d]\r", check_num); } else { printf("你输入的验证码是:[%d]\r\n", num);//进入下一次循环后,从键盘输入的为验证码 //printf("输入的验证码:%d,真正的验证码%d\r\n", num, check_num); if (employee_check_num_check(num, check_num))//1 0 { employee_zhangsan->work[my_time->day].check_in = *my_time; employee_zhangsan->work[my_time->day].check_in_flag = 1; printf("上班打卡成功!\r\n"); input_flag = 0; } } } } void work_out_end(my_time_t* my_time, employee_info_t* employee_zhangsan) { int num = 0; static int flag = 0; int result=0; result=employee_info_get(&num); if (result == 1) { if (flag == 0) { printf("此时num的值为%d,是否", num); printf("此时张同学的信息是:%d\r\n", employee_zhangsan->base); flag++; } } if (num == employee_zhangsan->base) { employee_zhangsan->work[my_time->day].check_out = *my_time; employee_zhangsan->work[my_time->day].check_out_flag = 1; //printf("这时候的我的时间正常吗?%d:%d\r\n", my_time->day, my_time->hour); //printf("这个时候的员工时间正常吗?%d:%d\r\n", employee_zhangsan->work[1].check_out.day, employee_zhangsan->work[1].check_out.hour); printf("下班打卡成功\r\n"); } } void show_punch_menu(my_time_t* my_time, employee_info_t* employee_zhangsan) { int i = 0; static unsigned int punch_flag = 0; if (my_time->day < 6 && my_time->hour == 21) { if (punch_flag == 0) { printf("check in\t\t\tcheck out\n"); printf("[%d][%d]\t\t[%d][%d] \n", employee_zhangsan->work[1].check_in.day, employee_zhangsan->work[1].check_in.hour, employee_zhangsan->work[1].check_out.day, employee_zhangsan->work[1].check_out.hour); punch_flag++; } } if (my_time->day == 6&&my_time->hour==1) { punch_flag = 0; if (punch_flag == 0) { printf("check in\t\t\t check out\n"); for (i = 0; i < my_time->day; i++) { printf("[%d][%d]\t\t[%d][%d] \n", employee_zhangsan->work[i].check_in.day, employee_zhangsan->work[i].check_in.hour, employee_zhangsan->work[i].check_out.day, employee_zhangsan->work[i].check_out.hour); } punch_flag++; } } } void time_run(my_time_t* my_time) { static unsigned int time_flag = 0;//标记时间点。到六秒时间加一小时,标记归零 static unsigned int punch_flag = 0;//标记显示非打卡时间点 //printf("\n现在为您报时:%d:%d\r", my_time->day, my_time->hour); Sleep(1000);//s time_flag++; if (time_flag == 6) { my_time->hour++; time_flag = 0; } //显示打卡时间状态信息 if (my_time->hour == 7 && time_flag == 1) { if (_kbhit() == 0) { printf("上班打卡时间:星期%d时间%d:%d到12:00\r", my_time->day, my_time->hour, my_time->min); punch_flag = 0; } } else if (my_time->hour == 16 && time_flag == 1) { if (_kbhit() == 0) { printf("下班打卡时间%d:%d~20:00请输入员工编号打卡", my_time->day, my_time->hour); punch_flag = 0; } } else if (my_time->hour > 12 && my_time->hour < 16 || my_time->hour>20 || my_time->hour < 6) { if (punch_flag == 0) { printf("非打卡时间段\r\n"); punch_flag++; } if (_kbhit() != 0) { printf("未到打卡时间时间,请稍后\r\n"); _getch(); } } // if (my_time->hour == 24) { my_time->day++; my_time->hour = 0; } } int clockin_machine_start() { employee_info_t employee_zhangsan; my_time_t my_time; int day_paper_flag = 0; char result = 0, input_flag = 0; memset(&employee_zhangsan, 0, sizeof(employee_info_t));//将张三的信息初始化为0 memset(&my_time, 0, sizeof(my_time));//将我的时间初始化为0 //monday 7:00 my_time.hour = 7; my_time.min = 0; my_time.sec = 0; my_time.day = 1; while (1) { time_run(&my_time);//时间开始流逝 /* 判断时间,周一到周五7点到9点可以进行上班打卡,在上班打过卡的情况下, 时间为16点到20点可以进行下班打卡,在周六展示员工一周的打卡情况; */ if (my_time.hour >= 7 && my_time.hour < 12)//时间7点到9点,可以上班打卡 { work_in_start(&my_time, &employee_zhangsan); } else if (my_time.hour >= 16 && my_time.hour < 20 && employee_zhangsan.work[my_time.day].check_in_flag) { work_out_end(&my_time, &employee_zhangsan); } show_punch_menu(&my_time, &employee_zhangsan); } } int main(int argc, int** argv) { clockin_machine_start(); return 0; }

    笔者敬告

    Processed: 0.016, SQL: 8