多文件编译任务:员工考勤信息管理

tech2026-03-10  0

多文件编译任务:员工考勤信息管理

搭建框架主文件头文件自定义函数文件 运行流程cmt.hmain.ccmt.c

搭建框架

1、建立主文件main.c 2、编写自定义函数文件cmt.c 3、建立对应头文件cmt.h

主文件

1、包含头文件:#include <cmt.h> 2、声明存储信息的全局结构体变量以及对应指针 3、含有唯一主函数:int main() 4、含有专用的子函数和附加定义

// 员工信息录入,员工信息管理 // void staff_book(struct InfoM *stfm); // void start_staff_manager();

头文件

1、公开的宏定义

// 定义一些常用变量 // 并外部添加 #ifndef CMT_H_ #define CMT_H_ #endif 防止重定义

2、公开的结构体定义

// 该结构体类型可由声明该头文件的任意文件调用

3、公开的库函数声明

// 其中定义的子函数可由声明该头文件的任意文件调用

自定义函数文件

将之前的打卡机文件改成自定义的函数库文件 修改1:去除主函数

// 保留原有的子函数 // 开机函数、打卡函数、退卡函数 void clockin_machine_start(struct InfoM *stfm) int CardOn(struct InfoM *stfm, time_t tempClock); int CardOff(struct InfoM *stfm, time_t tempClock);

修改2:修改原先的结构体

// 采用内嵌结构体的形式 // 通常信息+考勤信息 // 该文件中的函数对通常信息仅做读取,对考勤信息可以修改

修改3:添加头文件包含:#include <cmt.h>

运行流程

1、声明全局构造类型变量 2、录入员工信息 3、打卡机操作流程 4、每周打卡信息整理 5、按工时排序 其中1、2、4、5操作在主文件main.c下定义; 3操作在库文件cmt.c下定义,经由头文件cmt.h声明实现主文件的调用。

cmt.h

/** 宏定义与结构体定义 */ /** 模拟:每小时长度,转换为实际分钟 */ #define HOUR 6 #define TRANS 10 //60/6 #define POWER 7 #define WEEKDAY 5 #define STUFF 4 #define NUMS 6 #ifndef CMT_H_ #define CMT_H_ /** 员工考勤表 */ struct Info { //char code[NUMS]; int Schedule[2]; //每日上下班时间 int L; //迟到 int E; //早退 int X; //旷工 int F; //全勤 int D[5]; //每周持续上班时间 int AVED; }; /** 员工信息表 */ struct InfoM { char name[16]; char code[NUMS]; short age; char sex; char call[16]; char mail[32]; struct Info ct; }; /** 头文件中不能定义结构体数组 */ //struct InfoM stfm[STUFF]={}; /** 打卡操作声明 */ void clockin_machine_start(struct InfoM *stfm); #endif // CMT_H_

main.c

#include <stdio.h> #include <stdlib.h> #include "cmt.h" struct InfoM stfm[STUFF] = {}; struct InfoM st[STUFF] = {}; struct InfoM *p = &stfm[0]; void start_staff_manager(); void staff_book(struct InfoM *stfm); int main() { start_staff_manager(); return 0; } void start_staff_manager() { /** 录入员工信息 */ staff_book(p); /** 打卡操作 */ clockin_machine_start(p); /** 信息备份 */ FILE *fp; fp = fopen("result.txt","w+"); fwrite(&stfm,sizeof(stfm),1,fp); /** 将文件内部指针fp指向文件内容开头 */ rewind(fp); /** 信息读取 */ fread(&st,sizeof(st),1,fp); printf("员工姓名\t迟到\t早退\t旷工\t全勤\n"); for(int i=0; i<STUFF; i++) { printf("%s\t\t%d\t%d\t%d\t%d\n", st[i].name, st[i].ct.L, st[i].ct.E, st[i].ct.X, st[i].ct.F); } fclose(fp); /** 排序模块 */ for(int i=0; i<STUFF; i++) { /** 大--->小 */ for(int j=0; j<STUFF-i-1; j++) { if( st[j].ct.AVED < st[j+1].ct.AVED) { /** 注意 temp 的类型 */ struct InfoM temp = st[j]; st[j] = st[j+1]; st[j+1] = temp; } } } /** 输出排序结果 */ for(int i=0; i<STUFF; i++) { printf("第 %d 名是:%s,日工作时间为 %d\n", i+1, st[i].name, st[i].ct.AVED); } } /** 录入员工信息 */ void staff_book(struct InfoM *stfm) { for(int i=0; i<STUFF; i++) { printf("<<%d>>姓名:", i+1); gets(stfm[i].name); printf("<<%d>>确认姓名: %s\n", i+1, stfm[i].name); printf("<<%d>>编号(%d位):", i+1, NUMS); gets(stfm[i].code); printf("<<%d>>确认编号: %s\n", i+1, stfm[i].code); printf("<<%d>>年龄:", i+1); scanf("%hd", &stfm[i].age); getchar(); printf("<<%d>>确认年龄: %d\n", i+1, stfm[i].age); printf("<<%d>>性别(m/f):", i+1); scanf("%c", &stfm[i].sex); getchar(); printf("<<%d>>确认性别: %c\n", i+1, stfm[i].sex); printf("<<%d>>电话:", i+1); gets(stfm[i].call); printf("<<%d>>确认电话: %s\n", i+1, stfm[i].call); printf("<<%d>>邮箱:", i+1); gets(stfm[i].mail); printf("<<%d>>确认邮箱: %s\n", i+1, stfm[i].mail); } }

cmt.c

#include <stdio.h> #include <time.h> #include "cmt.h" /** 打卡操作定义 */ time_t TimeOn,TimeOff; int CardOn(struct InfoM *stfm, time_t tempClock); int CardOff(struct InfoM *stfm, time_t tempClock); void clockin_machine_start(struct InfoM *stfm) { /** 一、初始化模式*/ /** 1.1 员工信息录入与显示 */ //printf("---事先录入员工信息---\n"); /** 为防止跨文件后内存被释放,设置为静态变量 */ /** static:仅能在文件内部被使用 */ //struct Info ct[STUFF]={}; for(int i=0; i<STUFF; i++) { printf("<<%d>>确认姓名: %s\n", i+1, stfm[i].name); printf("<<%d>>确认编号: %s\n", i+1, stfm[i].code); printf("<<%d>>确认年龄: %d\n", i+1, stfm[i].age); printf("<<%d>>确认性别: %c\n", i+1, stfm[i].sex); printf("<<%d>>确认电话: %s\n", i+1, stfm[i].call); printf("<<%d>>确认邮箱: %s\n", i+1, stfm[i].mail); } /** 1.2 时间更新 */ int day = 1; /** 二、 工作模式 */ while(day<=WEEKDAY) { /** 1 报时 */ printf("---星期 %d---\n", day); /** 2 模拟一天工作*/ /** 2.1 初始化各时间节点、员工起始表 */ time(&TimeOn); printf("!!!实际时间为: %s\n", ctime(&TimeOn)); for(int i=0; i<STUFF; i++){ stfm[i].ct.Schedule[0]=0; stfm[i].ct.Schedule[1]=0; } /** 2.2 初始化操作符、通常结束符、提前结束符 */ int opt; int flag_uni = 1; int flag_cnt = 0; /** 2.3 功能循环放送(整天内可以随时打/退卡) */ while(flag_uni) { printf("--*--1.打卡--*--2.退卡--*--\n>>"); scanf("%d", &opt); getchar(); /** 2.3.1 打卡操作 */ if(opt==1) { /** 2.3.1.1 避免子函数内定义造成计时紊乱 */ time_t tempClock; /** 2.3.1.2 打卡操作子程序 */ int tempId = CardOn(stfm, tempClock); /** 2.3.1.3 打卡反馈信息 */ if(tempId != -1){ /** 显示信息 */ printf("$ %s 上班时间为 ", stfm[tempId].name); int Gap = stfm[tempId].ct.Schedule[0]-TimeOn; printf(" %d : %2d", Gap/HOUR + POWER, Gap%HOUR*10); /** 记录信息:弹性迟到法则 */ if(stfm[tempId].ct.Schedule[0]-TimeOn <= 2*HOUR){ printf(",今日按时到岗。\n"); }else if(day>1 && stfm[tempId].ct.D[day-2]>=10*HOUR && stfm[tempId].ct.Schedule[0]-TimeOn<=4*HOUR){ printf(",昨日加班,不算迟到。\n"); }else{ printf(",上班迟到,予以警告!\n"); stfm[tempId].ct.L++; } } /** 2.3.2 退卡操作 */ }else if(opt==2){ /** 2.3.2.1 避免子函数内定义造成计时紊乱 */ time_t tempClock; /** 2.3.2.2 退卡操作子程序 */ int tempId = CardOff(stfm, tempClock); /** 2.3.2.3 退卡反馈信息 */ if(tempId != -1){ /** 所有人都下班时,自动关机 */ flag_cnt++; if(flag_cnt == STUFF) flag_uni = 0; /** 显示信息 */ printf("$ %s 下班时间为 ", stfm[tempId].name); int Gap = stfm[tempId].ct.Schedule[1]-TimeOn; printf(" %d : %2d", Gap/HOUR + POWER, Gap%HOUR*10); /** 记录信息:工作时长,早退 */ int tempDuration = stfm[tempId].ct.Schedule[1]-stfm[tempId].ct.Schedule[0]; stfm[tempId].ct.D[day-1] = tempDuration; if(tempDuration < 8*HOUR){ stfm[tempId].ct.E++; printf(",早退 %d 分钟,予以警告!\n", (8*HOUR-tempDuration)*10); }else{ printf(",多工作 %d 分钟,", (tempDuration-8*HOUR)*10); /** 全勤判断:既不迟到也不早退 */ if(stfm[tempId].ct.Schedule[0]-TimeOn <= 2*HOUR){ stfm[tempId].ct.F++; printf("全勤鼓励!\n"); }else if(day>1 && stfm[tempId].ct.D[day-2]>=10*HOUR && stfm[tempId].ct.Schedule[0]-TimeOn<=4*HOUR){ stfm[tempId].ct.F++; printf("全勤鼓励!\n"); } } } } /** 2.3.3 重置操作符 */ opt = 0; /** 2.3.4 是否到达截止时间并关机 */ time(&TimeOff); if(TimeOff >= TimeOn + 17*HOUR){ printf("%s\n", ctime(&TimeOff)); printf("PowerOff!\n"); flag_uni = 0; /** 2.3.3.1 每日结算,是否有旷工*/ for(int i=0; i<STUFF; i++){ if(stfm[i].ct.Schedule[1]==0 || stfm[i].ct.Schedule[1]==0){ stfm[i].ct.X++; printf("%s 今日旷工\n", stfm[i].name); } } } } /** 每日总结 */ printf("-*-星*期*%d*总*结-*-\n", day); printf("员工姓名\t迟到\t早退\t旷工\t全勤\n"); for(int i=0; i<STUFF; i++){ printf("%s\t\t%d\t%d\t%d\t%d\n", stfm[i].name, stfm[i].ct.L, stfm[i].ct.E, stfm[i].ct.X, stfm[i].ct.F); //printf("%s\t\t%d\t%d\t%d\t%d\n", stfm[i].ct.code, stfm[i].ct.L, stfm[i].ct.E, stfm[i].ct.X, stfm[i].ct.F); //printf("%x\t\t%x\t%x\t%x\t%x\n", &stfm[i].name, &stfm[i].ct.L, &stfm[i].ct.E, &stfm[i].ct.X, &stfm[i].ct.F); } day++; } printf("-*-*-周-*-总-*-结-*-*-\n"); for(int i=0; i<STUFF; i++){ stfm[i].ct.AVED = stfm[i].ct.D[0]; for(int j=1; j<WEEKDAY; j++){ stfm[i].ct.AVED += stfm[i].ct.D[j]; } stfm[i].ct.AVED = stfm[i].ct.AVED *10/5; } printf("员工姓名\t平均到岗时间\n"); for(int i=0; i<STUFF; i++){ printf("%s\t\t%d\n", stfm[i].name, stfm[i].ct.AVED); } printf("回车\n"); getchar(); //printf("\n p : %x", p); } /** 打卡程序 */ int CardOn(struct InfoM *stfm, time_t tempClock) { /** 设置缓冲区,比较符 */ char tempCode[NUMS]; printf("上班打卡模式\n"); int bingo = 0; /** 打卡输入模块 */ while(!bingo){ time(&tempClock); printf("请输入工号:\n"); gets(tempCode); for(int i=0; i<STUFF; i++){ bingo = 1; for(int j=0; j<NUMS; j++){ /** 若不匹配,则下一个 */ //if(tempCode[j]!=stfm[i].ct.code[j]){ if(tempCode[j]!=stfm[i].code[j]){ bingo = 0; break; } } /** 若完全匹配,则停止for循环 */ if(bingo==1){ if(stfm[i].ct.Schedule[0]!=0){ /** 重复打卡 */ printf("请勿重复打卡!\n"); }else{ /** 首次打卡 */ stfm[i].ct.Schedule[0] = tempClock; return i; } break; }; } /** 查无此号:继续尝试or重新选择操作 */ if(bingo==0){ printf("不存在此工号\n"); printf("是否退出?\n1.是\t0.否\n>>>"); scanf("%d", &bingo); getchar(); if(bingo==1) printf("退出成功\n"); } } return -1; } /** 退卡程序 */ int CardOff(struct InfoM *stfm, time_t tempClock) { /** 设置缓冲区,比较符 */ char tempCode[NUMS]; printf("下班退卡模式\n"); int bingo = 0; /** 退卡输入模块 */ while(!bingo){ time(&tempClock); printf("请输入工号:\n"); gets(tempCode); for(int i=0; i<STUFF; i++){ bingo = 1; for(int j=0; j<NUMS; j++){ /** 不匹配则下一个 */ //if(tempCode[j]!=stfm[i].ct.code[j]){ if(tempCode[j]!=stfm[i].code[j]){ bingo = 0; break; } } /** 完全匹配 */ if(bingo==1){ /** 比打卡操作多了这一步 */ if(stfm[i].ct.Schedule[0]==0){ printf("尚未打卡,强制退出!\n"); }else{ if(stfm[i].ct.Schedule[1]!=0){ printf("请勿重复退卡!\n"); }else{ stfm[i].ct.Schedule[1] = tempClock; return i; } } break; }; } if(bingo==0){ printf("不存在此工号\n"); printf("是否退出?\n1.是\t0.否\n>>>"); scanf("%d", &bingo); getchar(); if(bingo==1) printf("退出成功\n"); } } return -1; }
最新回复(0)