打卡机核心功能实现(C语言)
任务分析
应市场需求,某工程师现设计了一款新上下班打卡机,打卡机具有以下功能:
(1)上班打卡,员工具有编号(首位为 1 的六位编号),输入编号后,再输入校验码,校验码生成规则:员工编号除首位反序,再与员工编号求和,如:员工编号,110086,校验码为 178087。校验码错误即打卡失败。记录打卡时间 。
(2)下班打卡,只需输入员工编号即可。记录打卡时间,显示该人员今天上班时长,如果上班时长不够,显示早退 xx 分钟。可以更新下班打卡时间。无下班打卡显示缺卡。
(3)可以设置规定上班时长,如 9 小时
(4)测试需要可以规定 6 秒=实际 1 小时,每次测试,输入指令后,开启打卡机,打卡机开启模拟时间为:周一早上七点。程序运行结束为周五晚 12 点。
(5)实行弹性打卡制,如前一天上班时长超过规定时长 3 小时以上,第二天迟到 2 小时以内不算迟到。
(6)打卡机运行结束之前,每周该打卡机会生成每周考勤周报,显示周平均上班时长,周迟到,早退,缺卡次数等。
要求:合理定义所需函数,主函数中只允许有 clockin_machine_start() 调用。
任务要求是主函数中只允许有clockin_machine_start()
的调用,因此在主函数中仅进行该函数的调用,具体实现放在主函数外部。
int main()
{clockin_machine_start();return 0;
}
将任务划分为三个主要的模块,分别是员工上班打卡、下班打卡、时间统计与处理。
首先是员工上班打卡的实现,打卡所需的工作封装在ClockIn()
函数中,该函数传入的参数含义分别为编号、验证码和编号长度,其中InitInfor()
函数用于实现员工编号和验证码的录入,其中包括信息格式的判断,并通过CheckInfor(id, captcha, size)
函数来判断录入的信息内容是否通过校验。
void ClockIn(char id[SIZE], char captcha[SIZE], int size)
{while(1){printf("Please input the id:>"); InitInfor(id, size);printf("Please input the code:>"); InitInfor(captcha, size);if(CheckInfor(id, captcha, size) == 0){printf("Ok! You've clocked in.'\n");break;}else if(CheckInfor(id, captcha, size) != 0){printf("Sorry, please input the right infor.\n");} }
}
第二部分是员工下班打卡,因为下班只需要输入员工编号,所以此时传入参数为员工编号和编号长度,将下班打卡时录入的信息与员工编号进行匹配,如果匹配成功,则打卡成功。
void ClockOut(char id[SIZE], int size)
{char id_buf[SIZE] = {'0'};while(1){printf("Please input the id:>");InitInfor(id_buf, size);if(memcmp(id_buf, id, size) == 0){printf("Ok! You've clocked out.\n");break;}else if(memcmp(id_buf, id, size) != 0){printf("Sorry, please input the right infor.\n");}}
}
第三部分为时间管理,通过time()
函数来记录当前程序语句运行时的时间,通过对多个程序点的时间计算,完成员工上班工作时长、迟到、早退等信息的统计。
time_t clockin_time;
time(&clockin_time);
因为打卡机在周内要一直执行,此时就需要在每个阶段进行时间的获取及处理,但是在打卡机功能中,有这样一个需求,员工在每天工作结束后如果无下班打卡则记为缺卡,但是如果要实现该功能,则程序获取输入与程序统计时间就会产生矛盾,员工一直没有输入,则程序处于获取输入的阻塞状态中,那么时间就无法计算。
在Linux系统下可以通过以下方法解决此问题:(使用非阻塞IO)
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>int flag1, flag2;
if(flag1 = fcntl(STDIN_FILENO, F_GETFL, 0) < 0)
{perror("fcntl");return -1;
}
flag2 = flag1 | O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, flag2); //非阻塞// 执行动作fcntl(STDIN_FILENO, F_SETFL, flag1); //阻塞
代码实现
clockin_machine.h
#ifndef __CLOCKIN_MACHINE_H__
#define __CLOCKIN_MACHINE_H__#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>#define SIZE 6 // bits of id
#define WEEKDAY 5 // weekday
#define ONEDAY 86400 // ONEDAY is 86400s long
#define TWOHOUR 7200 // TWOHOUR is 86400s long
#define THREEHOUR 10800 // THREEHOUR is 86400s long
#define ALL 0 // ALL is the first line of the time table, means working time
#define IN 1 // ALL is the second line of the time table, means clock_in time
#define OUT 2 // ALL is the third line of the time table, means clock_out timetime_t start_time; // the machine start at 7 am Mon.
int open_time; // clock_in time = 9 am
int close_time; // clock_out time = 5 pm
int work_time[3][WEEKDAY]; // time table
int arrive_late;
int leave_early;void clockin_machine_start();
void BannerIn(int day);
void ClockIn(char id[SIZE], char captcha[SIZE], int size);
void InitInfor(char buf[SIZE], int size);
int CheckInfor(char id[SIZE], char captcha[SIZE], int size);
void BannerOut();
void ClockOut(char id[SIZE], int size);
void BannerFin(int day);
time_t reTime(time_t time);
void CountTime(time_t clockin_time, time_t clockout_time, int day);
void IsArriveLate(int day);
void IsLeaveEarly(int day);
int AverageTime(int weekday);
void DisplayCount(int ave_time, int arrive_late, int leave_early);#endif //__CLOCKIN_MACHINE_H__
main.c
#include "clockin_machine.h"int main()
{clockin_machine_start();return 0;
}
clockin_machine.c
#include "clockin_machine.h"void clockin_machine_start()
{time(&start_time);start_time = reTime(start_time);open_time = start_time + TWOHOUR; close_time = start_time + (10 * TWOHOUR);arrive_late = 0;leave_early = 0;int day = 0;do{char id[SIZE] = {'0'}; // the id of the employee char captcha[SIZE] = {'0'}; // identificationBannerIn(day);ClockIn(id, captcha, SIZE); // clock intime_t clockin_time;time(&clockin_time); // write down the time of clocking inclockin_time = reTime(clockin_time); // change the form of the timeBannerOut();ClockOut(id, SIZE); // clock out time_t clockout_time;time(&clockout_time); // write down the time of clocking outclockout_time = reTime(clockout_time); // change the form of the timeCountTime(clockin_time, clockout_time, day); // count the worker's information all day IsArriveLate(day); // did the worker arrive late IsLeaveEarly(day); // did the worker leave earlyBannerFin(day);day++; }while(day < WEEKDAY);int ave_time = AverageTime(WEEKDAY);DisplayCount(ave_time, arrive_late, leave_early);}void BannerIn(int day)
{switch(day+1){case 1:printf("Mon.\n");break;case 2:printf("Tue.\n");break;case 3:printf("Wed.\n");break;case 4:printf("Thur.\n");break;case 5:printf("Fri.\n");break;default:break;}printf("****************************************\n"); printf("------------please clock in-------------\n");
}void ClockIn(char id[SIZE], char captcha[SIZE], int size)
{while(1){printf("Please input the id:>"); InitInfor(id, size);printf("Please input the code:>"); InitInfor(captcha, size);if(CheckInfor(id, captcha, size) == 0){printf("Ok! You've clocked in.'\n");break;}else if(CheckInfor(id, captcha, size) != 0){printf("Sorry, please input the right infor.\n");} }}void InitInfor(char buf[SIZE], int size)
{int index = 0;char tmp;while((tmp=getchar()) != '\n'){buf[index] = tmp;index++;}if(index!=size || buf[0]!='1'){printf("Sorry, please input the right infor:>");InitInfor(buf, size);}
}int CheckInfor(char id[SIZE], char captcha[SIZE], int size)
{// if the code is right, retunr 0int i = 0;char tmp[size];strncpy(tmp, id, size);// Except for the first number of employees, sum up in reverse order for(i=1; i<size; i++){tmp[i] = (char)(((int)tmp[i])%48 + (int)id[size-i]); }return strcmp(tmp, captcha);
} void BannerOut()
{printf("------------please clock out------------\n");
}void ClockOut(char id[SIZE], int size)
{char id_buf[SIZE] = {'0'};while(1){printf("Please input the id:>");InitInfor(id_buf, size);if(memcmp(id_buf, id, size) == 0){printf("Ok! You've clocked out.\n");break;}else if(memcmp(id_buf, id, size) != 0){printf("Sorry, please input the right infor.\n");}}
}void BannerFin(int day)
{int hour = work_time[ALL][day] / 3600;int min = (work_time[ALL][day] - hour * 3600) / 60;printf("***************You worked%3dhour%3dmin**\n\n\n", hour, min);
}time_t reTime(time_t time)
{return time%ONEDAY;
}void CountTime(time_t clockin_time, time_t clockout_time, int day)
{work_time[ALL][day] = (clockout_time - clockin_time) * 10 * 60;work_time[IN][day] = clockin_time;work_time[OUT][day] = clockout_time;
}void IsArriveLate(int day)
{if(day > 0){if(work_time[OUT][day-1]-close_time >= THREEHOUR)//work hard last day {if(work_time[IN][day]-open_time <= TWOHOUR){}else if(work_time[IN][day]-open_time > TWOHOUR)// over two hours{arrive_late++;}}else if(work_time[OUT][day-1]-close_time < THREEHOUR)// did not work hard {if(work_time[IN][day] <= open_time){}else if(work_time[IN][day] > open_time)//arrive late{arrive_late++;}}}else if(day == 0) // if today is Mon.{if(work_time[IN][day] <= open_time){}else if(work_time[IN][day] > open_time)//arrive late{arrive_late++;}}
} void IsLeaveEarly(int day)
{if(work_time[OUT][day] >= close_time){}else if(work_time[OUT][day] < close_time){leave_early++;}
}int AverageTime(int weekday)
{int i = 0;int sum = 0;for(i=0; i<weekday; i++){sum = sum + work_time[ALL][i];}return sum/weekday;
}void DisplayCount(int ave_time, int arrive_late, int leave_early)
{int hour = ave_time / 3600;int min = (ave_time - hour * 3600) / 60;printf("vvvvvvvvvvvvv SUM vvvvvvvvvvvv\n");printf("··average time> %2dh%2dm\n", hour, min);printf("··arrive late > %dtimes\n", arrive_late);printf("··leave early > %dtimes\n", leave_early);
}