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

搭建框架

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值