工资管理系统/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