工资管理系统/c语言期末大作业学习经历-创新互联

大致流程

这次大作业开始构思到写完程序并测试完毕,经历了两周多的努力。在初步分化好模块之后,在网上找各种资料学习链表(比较推荐翁恺老师的课),后边又学习了一些相对应的知识,像是链表的排序算法(因为精力有限只学了插入排序)。准备工作做完之后,刚开始编写程序就遇到了Segment fault报错,因为是第一次用链表,对于这种报错完全是一头雾水,问了好几个同学,改了好几天。最后实在没办法,又从头写了一遍。虽然现在回过头来看,这玩意也没那么难,但是实际学习过程中真是不简单。

成都创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站设计、做网站、成都外贸网站建设公司、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的盂县网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

因为想做一个模块化的程序,每一个都可以配合mian函数独立使用,所以像是遍历,输入文件这样的功能重复出现了好几次。

函数功能实现及参数分析

1,结构体声明

Worker结构体包含了员工的工号,姓名,基本工资。奖金,扣款,应发工资,实发工资和税款信息;

List结构体包含了链表的头指针(head)和尾指针(tail),当对包含头指针和尾指针的结构体修改的函数结束后,虽然结构体不会保存,但指针所指向的地址已经被修改了,为函数省去了需要return的部分

2,Main函数

Main函数实现了读取文件,链表创建和模块选择的功能;

变量Option用于控制switch结构,对执行模块进行选择;变量n用于创建链节时判断当前链节是否为头节点。结构体指针emp1和p两个临时变量,指针temp1负责指向malloc函数开辟出的内存区域,并承接文件传进来的数据。指针p每次循环负责将前一个链节的指针指向后一个链节,并将指向后一个链节,以此延长链表。Boolean变量负责判断while循环内的switch函数是否执行,switch函数负责调用各大模块的函数。

3,输出,查找,修改,删除函数主体都有链表的遍历

输出操作,就是f临时指针,for循环遍历链表,遍历的同时,使用printf函数打印出来

查找操作,就是f临时指针,赋给头指针的值,for循环遍历链表,找到与工号相匹配的链节,printf将其输出出来。

修改操作,f临时指针,for循环遍历链表,找到匹配链节后,scanf对该链节数据重新输入,并计算其他数据。

删除操作,f和p为临时指针,f指向待删除结点,p指向前一个结点,连接待删除结点的前后两个链节,释放该链节的空间,并使指针指向为空

4,排序函数

指针lastSorted指向已经参与排序的部分的末尾链节,

指针curr指向下一步待插入到已排列部分的链节;

指针prev指向待插入链节在已排列部分该插入位置的前一个链节;

指针dummyhead便于在头结点插入链节;

在链表前端人为创造一个已排序的有序部分,初始时只有一个头节点,curr指针指向lastSorted后方第一个链节。此时从已排序部分遍历,找到刚好小于等于它的结点,将curr结点插入到该结点后方,再完成指针的链节。直到链表中的所有元素都加入到有序的部分,这个链表也就完成了排序;

首先做好函数声明与结构体声明

#include#include#include#include#define LEN sizeof(Worker)

typedef struct _Worker
{
    int num;                //工号
    char name[20];            //姓名
    float base_salay;        //基本工资 
    float bonus;            //奖金 
    float fine;                //扣款 
    float salay;            //应发工资 
    float real_salay;        //实发工资 
    float tax;                //税款 
    struct _Worker *next;    //指向下一链节的指针 
} Worker;

typedef struct _list //便于传递头指针和尾指针,程序执行完毕可以不使用return
{
    Worker *head;//头指针
    Worker *tail;//尾指针
}List;

    void Menu();                        //菜单函数
    void Print(List list);               //输出函数
    void Add(List list);                //增添函数
    void Delate(List list);             //删除函数
    void Amend(List list);              //修改函数
    void Seek(List list);                //查找函数
    void Sort(List list);               //排序函数
    void Statis(List list);             //统计函数

Worker结构体

是链表的基础,可分为两个部分,一部分是储存数据的

这个List结构是我在翁恺老师的c语言链表视频里学习到的,虽然是结构体,但他就只包含了两个指针。这两个指针分别指向头指针和尾指针。因为在一些函数里会对头指针,尾指针进行修改,而指针本身只是一个地址,所以在函数内修改后还需要返回值给main函数,为了方便一些,创建一个指针的指针

以下为全部代码,需配合对应txt文件使用

#include#include#include#include#define LEN sizeof(Worker)

typedef struct _Worker
{
    int num;                //工号
    char name[20];            //姓名
    float base_salay;        //基本工资 
    float bonus;            //奖金 
    float fine;                //扣款 
    float salay;            //应发工资 
    float real_salay;        //实发工资 
    float tax;                //税款 
    struct _Worker *next;    //指向下一链节的指针 
} Worker;

typedef struct _list //便于传递头指针和尾指针,程序执行完毕可以不使用return
{
    Worker *head;//头指针
    Worker *tail;//尾指针
}List;

    void Menu();                        //菜单函数
    void Print(List list);               //输出函数
    void Add(List list);                //增添函数
    void Delate(List list);             //删除函数
    void Amend(List list);              //修改函数
    void Seek(List list);                //查找函数
    void Sort(List list);               //排序函数
    void Statis(List list);             //统计函数

int main()
{
    List list;            //包含链表头指针和尾指针 
    int option;            //用于switch函数,对程序功能进行选择 
    int n=0;            //用于判断链表节点的位置 
    Worker *temp1,*p;    //两个临时指针,交替向后移动,以创建链表
    

    
    FILE *fp;
    if((fp=fopen("worker.txt","r+"))==NULL){
        printf("文件打开失败\n]");
        system("pause");//打开失败后按下按键即可退出程序
    }
    else{
        printf("文件打开成功\n");
            
    }//打开文件并对打开结果是否成功进行判断并提示


    while (feof(fp)==0)//while对文档中的数据进行读取
    {
        n++;
        temp1 = (Worker*)malloc(LEN);
        fscanf(fp,"%d %s %f %f %f %f %f %f",
           &temp1->num,&temp1->name,&temp1->base_salay,
           &temp1->bonus,&temp1->fine,&temp1->salay,&temp1->real_salay,&temp1->tax);
           
    
        temp1->next=NULL;
        if (n==1){
            list.head=temp1;//头指针 
        }
        else 
            p->next=temp1;
        p=temp1;
    }
    list.tail=p;//尾指针
    printf("文件数据读入完成\n");
    fclose(fp);//文件关闭
    fp=NULL;
    
    
    int boolean=1;//布尔值,用于判断while是否进行 
    
    do{
        Menu();                //程序打开后先输出菜单栏目     
        printf("\n请输入与模块相对应的数字进行使用\n"); 
        scanf("%d",&option);
        //do while 循环,实现一次打开,多次使用 

    switch(option)
    {
        case 1:
            Print(list);//输出函数 
            break;    
        case 2:
            Add(list);//增添函数 
            break;
        case 3:
            Delate(list);//删除函数 
            break;
            
        case 4:
            Amend(list);//修改函数 
            break;
            
        case 5:    
            Seek(list);//查找函数 
            break;
            
        case 6:
            Sort(list);//排序函数 
            break;    
        case 7:
            Statis(list);//统计函数 
            break;
                 
        default:
            printf("选择输入错误,请重新选择\n");
            break;
            
    }
        printf("\n如果继续使用程序请输入1,结束使用则输入0\n");
        scanf("%d",&boolean);
        system("cls");    
}while(boolean==1);
   
    return 0;

}
void Menu()
{
    printf("\n\n\t欢迎使用工资信息管理系统\n");
    printf("\t本程序含有以下功能模块\n");
    printf("\t请输入与模块相对应的数字进行使用\n");
    printf("\n\t--------工资信息管理系统---------\n"
            "\t|1.输出模块\t\t\t|\n"                    
            "\t|2.添加模块\t\t\t|\n" 
            "\t|3.删除模块\t\t\t|\n"
            "\t|4.修改模块\t\t\t|\n"
            "\t|5.查找模块\t\t\t|\n"
            "\t|6.排序模块\t\t\t|\n"
            "\t|7.统计模块\t\t\t|\n"
            "\t---------------------------------\n");
}



void Print(List list)
{
    Worker *f=list.head;
    printf("\n工号   姓名            基本工资  奖金      扣款      应发工资  实发工资  税款\n");
    for(;f;f=f->next)
    {
        printf("%-6d %-15s %-9.2f %-9.2f %-9.2f %-9.2f %-9.2f %-9.2f\n"
        ,f->num,f->name,f->base_salay,f->bonus,f->fine,f->salay,f->real_salay,f->tax);
    }
        
}

void Seek(List list)
{
    int number;
    Worker *f; //临时指针 
    printf("\n请输入你要查找的员工号\n");
    scanf("%d",&number);
    f=list.head;//将头指针赋给临时指针 
    for (;f;f=f->next)
    {
        if(f->num==number){
            printf("查询成功\n");
            printf("\n工号   姓名       基本工资  奖金      扣款      应发工资  实发工资  税款\n");
            printf("%-6d %-10s %-9.2f %-9.2f %-9.2f %-9.2f %-9.2f %-9.2f\n"
            ,f->num,f->name,f->base_salay,f->bonus,f->fine,f->salay,f->real_salay,f->tax);
            break;
        }
    } //遍历链表,将员工号与输入的数字相匹配 
}

void Add(List list)
{
    FILE *fp;//打开文件 
    if((fp=fopen("worker.txt","a+"))==NULL){
        printf("文件打开失败\n");
        exit(0);
    }

    Worker *f;//临时指针 
    int boolean;
    do{
        f=(Worker*)malloc(LEN);//由malloc函数 
        printf("\n请输入你要添加的员工信息\n"
        "依次为\n员工号 姓名 基本工资 奖金 扣款\n");
        scanf("%d %s %f %f %f",&f->num,f->name,&f->base_salay,&f->bonus,&f->fine);
        
        printf("\n如果继续添加员工信息请输入1,结束输入则输入0\n");
        scanf("%d",&boolean);
        
        f->salay=f->base_salay-f->fine+f->bonus;//应发工资的计算 
        
        if(f->salay<=5000)
            f->tax=0;
        else if(f->salay<=6500)
            f->tax=(f->salay-5000)*0.03;
        else if(f->salay<=9500)
            f->tax=(f->salay-5000)*0.1-105;
        else if(f->salay<=14000)
            f->tax=(f->salay-5000)*0.2-555;
        else if(f->salay<=40000)
            f->tax=(f->salay-5000)*0.25-1005;
        else if(f->salay<=60000)
            f->tax=(f->salay-5000)*0.3-2755;
        else if(f->salay<=85000)
            f->tax=(f->salay-5000)*0.35-5505;
        else
            f->tax=(f->salay-5000)*0.45-13505;
            //税款计算      
        f->real_salay=f->salay-f->tax;//实发工资
        
        fprintf(fp,"\n%d %s %f %f %f %f %f %f"
        ,f->num,f->name,f->base_salay,f->bonus,f->fine,f->salay,f->real_salay,f->tax);
        //将新开辟的空间所储存的数据 
        list.tail->next=f; //将新链节与链表相连 
        list.tail=list.tail->next;//更新尾指针
        list.tail->next=NULL;//保持尾指针的next指针指向为空 
        printf("输入成功\n");         
    }while (boolean!=0);
    fclose(fp);//关闭文件 
    fp=NULL;
}

void Delate(List list)
{
    FILE *fp;
    if((fp=fopen("worker.txt","w+"))==NULL){
        printf("文件打开失败\n]");
        exit(0);
    }
    //打开文件 
    int number;//员工号码 
    printf("\n请输入要删除的员工信息的员工号\n");
    scanf("%d",&number);
    Worker *f=list.head;//临时指针,将头指针赋给它 
    Worker *p=NULL; //临时指针 
    for(;f;p=f,f=f->next)//f为所求链节,p为前一链节 
    {
        if(f->num==number)
        {
            printf("你正在删除的员工姓名为%s\n",f->name);
            if(f==list.head){//特殊情况,删除头节点 
                list.head=f->next;
            }
            else{
                if(f==list.tail){//特殊情况,删除尾结点 
                    list.tail=p;
                    list.tail->next=NULL;
                }
                else{
                    p->next=f->next;//将前一链节的next指针,指向f的后一链节,以此跳过f,重新连接链表 
                }
            }
            free(f);//释放空间 
            break;
            f=NULL;//指针赋空 
        }        
    }
    printf("删除成功,正在同步至文本文件\n");
    for(f=list.head;f;f=f->next)
        {
        fprintf(fp,"\n%d %s %f %f %f %f %f %f"
        ,f->num,f->name,f->base_salay,f->bonus,f->fine,f->salay,f->real_salay,f->tax);
        }//将整个链表重新输入到文件中 
        printf("同步成功\n");
        fclose(fp);//文件关闭 
        fp=NULL; //指针赋空 
}

void Amend(List list)
{
    FILE *fp;//文件打开 
    if((fp=fopen("worker.txt","w+"))==NULL){
        printf("文件打开失败\n]");
        exit(0);
    }
    
    int number;
    printf("\n请输入要修改的员工信息的员工号\n");
    scanf("%d",&number);
    Worker *f;
    Worker *p=NULL; 
    //f和p都是临时指针 
    for(f=list.head;f;f=f->next)//链表遍历并寻找该链节 
    {
        if(f->num==number)
        {
            printf("将要修改信息的员工姓名为%s\n",f->name);

            printf("请重新输入该员工的信息\n"
                    "依次为 员工号 姓名 基本工资 奖金 扣款\n");
            scanf("%d %s %f %f %f",&f->num,f->name,&f->base_salay,&f->bonus,&f->fine);

            f->salay=f->base_salay-f->fine+f->bonus;//应发工资的计算 
        
            if(f->salay<=5000)
                f->tax=0;
            else if(f->salay<=6500)
                f->tax=(f->salay-5000)*0.03;
            else if(f->salay<=9500)
                f->tax=(f->salay-5000)*0.1-105;
            else if(f->salay<=14000)
                f->tax=(f->salay-5000)*0.2-555;
            else if(f->salay<=40000)
                f->tax=(f->salay-5000)*0.25-1005;
            else if(f->salay<=60000)
                f->tax=(f->salay-5000)*0.3-2755;
            else if(f->salay<=85000)
                f->tax=(f->salay-5000)*0.35-5505;
            else
                f->tax=(f->salay-5000)*0.45-13505;//税款计算 
                
                f->real_salay=f->salay-f->tax;//实发工资 
            break;   
        }        
    }

    printf("修改成功,正在同步至文本文件\n");
    for(f=list.head;f;f=f->next)
        {
        fprintf(fp,"\n%d %s %f %f %f %f %f %f"
        ,f->num,f->name,f->base_salay,f->bonus,f->fine,f->salay,f->real_salay,f->tax);
        }//链表同步至文件 
        printf("同步成功\n");
        fclose(fp);//文件关闭 
        fp=NULL; //指针赋空 
}


void Statis(List list)
{//求薪资最高的人的名字,和平均薪资
    Worker *f;//临时指针,薪资最高
    Worker *max;
    max=NULL;//指向为空
    float sum,average;//总和,平均工资
    int n=1;//记录人数
    sum=0;
    for(max=f=list.head;f->next;n++,f=f->next)
    {
        sum=f->real_salay+sum;//求和
        if(f->real_salay>=max->real_salay)
            {
                max=f;//f和f所指的进行比较
            }
            
    }
    average=sum/n;//用和求平均
    printf("员工平均薪资为%f\n薪资最高的员工是%s\n",average,max->name);
}

void Sort(List list)
{
    FILE *fp;//文件打开 
    if((fp=fopen("worker.txt","w+"))==NULL){
        printf("文件打开失败\n]");
        exit(0);
    }

    Worker* dummyHead=(Worker*)malloc(LEN);//哑节点,便于在头节点之前插入节点
    dummyHead->next=list.head;
    Worker *lastSorted;//已排序的最后一个链节
    Worker *curr;//待插入元素
    lastSorted=list.head;//初始时赋为头指针 
    curr=list.head->next;//待插入元素为第二个链节 
    
    while(curr)
    {
        if(lastSorted->num<=curr->num)//进行比较 
        {
            lastSorted=lastSorted->next;
        }
        else
        {
            Worker *prev=dummyHead;//待插入节点的前一个结点
            while(prev->next->num<=curr->num)
            {
                prev=prev->next;
            }
            //遍历链表,找到刚好小于待插入节点的那一个结点prev 
            lastSorted->next=curr->next;//将已排序的最后一个链节指向要交换的链节的下一个链节 
            curr->next=prev->next;//将待插入节点与prev的后方的链节相连 
            prev->next=curr;//将prev与待插入结点相连 
        }
        curr=lastSorted->next;//待插入结点重新定位到有序部分的后一个链节 
        list.head=dummyHead->next;//如果出现插入到头节点前方的现象,可以更新头节点 
    }

    Worker *f;
    printf("排序完成正在同步至文本文件\n");
    //链表同步至文件 
    for(f=list.head;f;f=f->next)
        {
        fprintf(fp,"\n%d %s %f %f %f %f %f %f"
        ,f->num,f->name,f->base_salay,f->bonus,f->fine,f->salay,f->real_salay,f->tax);
        }
    printf("同步成功\n");
}

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


分享文章:工资管理系统/c语言期末大作业学习经历-创新互联
网站URL:http://azwzsj.com/article/cshcop.html