工资管理系统设计论文.docx
《工资管理系统设计论文.docx》由会员分享,可在线阅读,更多相关《工资管理系统设计论文.docx(42页珍藏版)》请在冰豆网上搜索。
工资管理系统设计论文
工资管理系统
本程序旨在训练基本的编程能力,了解管理信息系统的开发流程,熟悉C语言的文件和结构数组的各种基本操作。
本程序中涉及结构体、数组、文件等方面的知识。
通过本程序的训练,使我对C语言的文件操作有了一个更深刻的了解,掌握利用数组存储结构实现工资管理的原理,为进一步开发出高质量的信息管理管理系统打下坚实的基础。
功能描述
如后图所示,与利用单链表实现的学生管理系统不同的是,此工资管理系统主要利用数组来实现,其数组元素是结构体类型。
整个系统由如下几大功能模块组成。
(1)输入记录模块。
输入记录模块主要完成将数据存入数组中的工作。
在此工资管理系统中,记录可以从以二进制形式存储的数据文件中读入,也可以从键盘逐个输入记录。
记录由职工的基本信息和工资信息字段构成。
当从数据文件中读入记录时,它就是在以记录为单位存储的数据文件中,将记录逐条复制到数组元素中。
(2)查询记录模块。
查询记录主要完成在数组中查询满足相关条件的记录。
在此工资管理系统中,用户可以按照职工编号或在数组中进行查找。
假设找到该记录,则以表格形式打印出此记录的信息;否则,返回一个-1的值,并打印出未找到该记录的提示信息。
(3)更新记录模块。
更新记录模块主要完成对记录的维护。
在此工资管理系统中,实现对记录的修改、删除、插入、和排序操作。
一般而言,系统进行了这些操作之后,需要将修改的的数据存入源数据文件。
1.主控main()函数执行流程
工资管理系统执行流程如后图所示。
它先以可读写的方式打开数据文件,此文件默认为“c:
\zggz”,如该文件不存在,则新建此文件。
当打开文件操作成功后,则从文件中一次读出一条记录,添加到新建的数组中,然后执行显示主菜单和进入主循环操作,进行按键判断。
在判断键值时,有效的输入为0~9之间的任意数值,其他输入都被视为错误按键。
假设输入为0〔即变量select=0〕,则会继续判断是否在对记录进行更新操作之后进行了存盘操作,假设未存盘,则全局变量saveflag=1,系统会提示用户是否需要进行数据存盘操作,用户输入Y或y,系统会进行存盘操作。
最后,系统执行退出工资管理系统的操作。
假设选择1,则调用Add()函数,执行增加记录操作;假设选择2,则调用Del()函数,执行删除记录操作;假设选择3,则调用Qur()函数,执行查询记录操作;假设选择4,则调用Modify()函数,执行修改记录操作;假设选择5,则调用Insert()函数,执行插入记录操作;假设选择6,则调用Tongji()函数,执行统计记录操作;假设选择7,则调用Sort()函数,执行按降序排序记录的操作;假设选择88,则调用Save()函数,执行将记录记录存入磁盘中的数据文件的操作;假设选择9,则调用Disp()函数,执行将记录以表格形式打印输出至屏幕的操作;假设输入0~9之外的值,则调用Wrong()函数,给出按键错误的提示。
2输入记录模块
输入记录模块主要实现将数据存入数组中。
当从数据文件中读出记录时,它调用fread(&gz[count],sizeof(ZGGZ),1,fg)文件读取函数,执行一次从文件中读取一条工资记录信息存入某个数组元素中德操作,并且这个操作在main()中调用执行,即在工资管理系统进入显示菜单界面时,该操作已经执行了。
假设该文件中没有数据,系统会提示数组为空,没有任何记录可操作,此时,用户应选择1,调用Add()函数,进行记录的输入,即完成在数组中添加元素的操作。
查询记录模块主要实现在数组中按职工编号或查找满足相关条件记录。
在查询函数Qur〔〕中,为了遵循模块化编程原则,我们将数组中进行的记录定位操作设计成了一个单独函数intLocate(ZGGZtp[],charfindmess[],charnameornum[]),参数findmess[]保存要查找的具体内容,nameornum[]保存要查找的字段〔职位字符串类型的num或者name〕,假设找到该记录,则返回指向该记录的数组元素的下标,否则;返回一个—1的值。
更新记录模块主要实现对记录的修改、删除、插入和排序操作。
因为记录是以数组的结构形式储存的,所以这些操作都在数组中完成。
下面分别介绍着4个功能模块。
1)修改记录
修改记录的操作需要对数组中目标元素的数域中的值进行修改,他分两步完成。
第一步,输入要修改的职员编号,输入后调用定位函数Locate〔〕在数组中逐个对职员编号字段的值进行比较,直到找到该职员的编号记录;第二步,假设找到该记录,则修改除职工编号之外的各字段的值,并将存盘标记变量savegflag置1,表示已经对记录进行了修改,但还未执行存盘操作。
2)删除记录
删除记录操作完成删除指定职员编号或的记录,他也分两步完成。
第一步,输入要修改的职员编号,输入后调用定位函数Locate〔〕在数组中逐个对职员编号字段的值进行比较,直到找到该职员的编号记录,并返回指向该记录的数组元素下标;第二步,假设找到该记录,则从该记录所在元素的后续元素起,依次向前移一个元素位置,有值的数组元素个数减1.
3)插入记录
插入记录操作完成在指定职工编号的随后位置插入新的记录。
搜先,他要求用户输入某个职工的职工编号,新的记录将插入在该记录之后;然后,提示用户数输入一条新的记录的信息,这些信息保存在心结构体类型的数组元素的个字段中;最后,将该元素插入已经确认的位置的职工编号之后。
它的具体插入执行过程如图7.3所示,新的元素B1准备插入至已有5个元素的数组中,插入位置为元素A2之后。
具体过程为:
先调用Locate〔〕函数找到A2在数组中的下标,从A4开始,往后移动,至A2停止移动,然后再原A3的位置插入元素B1.
4)排序记录
冒泡排序法属于内部排序中的一种,这是运用数据值比较后,一句判断规则对数据位置进行交换以到达排序的目的。
针对数组结构的特点,这里采用这种排序法莱实现按实发工资字段的值从高到底对记录进行排序。
冒泡排序法的基本思想为:
将相邻的两个数组远足的实发工资字段的值进行比较,假设左边的值小于右边的值,则将此两个元素的值进行交换;假设左边的值大于右边的值,则此两个值的位置不变。
右边的值继续和下一个值做比较,重复此动作,直到比较到最后一个值。
用伪代码描述如下:
插入B1
↓
A0
A1
A2
A3
A4
插入B1前
A0
A1
A2
B1
A3
A4
插入B1后
图7.3数据中插入记录示意图
if(左边的值<右边的值)then
此两个元素的位置互换;
else/*左边的值>=右边的值*/
此两个元素的位置不变:
右边的元素继续和下一个元素比较;
如图7.4所示,假设共有个ZGGZ结构数组元素gz【0】至gz【n-1】,其具体比较过程如下。
第一轮:
从gz【0】比到gz【n-1】,实发工资字段值最小的元素存放在gz【n-1】中。
第二轮:
从gz【0】比到gz【n-2】,实发工资字段值最小的元素存放在gz【n-2】中。
```````
第n-1轮:
从gz【0】比到gz【1】,实发工资字段值最小的元素存放在gz【1】中。
gz[n]
gz[0]
gz[1]
gz[2]
``````
gz[n-2]
gz[n-1]
图7.4数组中对记录
因为是按实发工资的降序排序,所以每进行一轮比较都会以交换位置的方式将该轮的最小者移向数据的尾端。
冒泡排序法的优点是,假设数组元素已有部分排好序,则使用冒泡排序法可以快速地完成排序。
其缺点则是会反复扫描数据,比较相邻的两个元素,速度不快且没有效率。
它属于稳定排序法。
该模块的实现比较简单,它主要通过依次读取数组中元素的数据域中的实发工资的值进行比较判断的形式,完成工资在各个等级的人数统计。
当把记录输出至文件时,调用fwrite(&tp[i],sizeof(ZGGZ),1,fp)函数,将数组元素tp[i]中各字段的值,写入文件指针fp所指的文件;当把记录输出至屏幕时,调用voidDisp()函数,将数组中存储的记录信息以表格的形式在屏幕上打印出来。
图7.2主控函数执行流程图
7.3.2数据结构设计
本程序定义了结构体emplee,用于存放职工的基本信息和工资信息。
typedefstructemployee/*标记为employee*/
{
charnum[10];
charname[15];
floatjbgz;
floatjj;
floatkk;
floatyfgz;
floatsk;
floatsfgz;
}ZGGZ;
其他字段的含义如下。
·num[10]:
保存职工编号。
·name[10]:
保存职工。
·jbgz:
保存职工基本工资。
·jj:
保存职工奖金。
·kk:
保存职工扣款。
·yfgz:
保存职工应发工资。
·sk:
保存职工税款。
·sfgz:
保存职工实发工资。
7.3.3函数功能描述
1〕printheader()
函数原型:
voidprintheader()
printheader()函数用于在以表格形式显示出记录时,打印输出表头信息。
2〕printdata()
函数原型:
voidprintada(ZGGZpp)
函数用于在以表格形式显示的方法,打印输出单个数组元素pp中的记录消息。
3)Disp()
函数原型:
voidDisp(ZGGZtp[],intn)
Disp()函数用于显示tp数组中存储的n条记录,内容为employee结构中定义的内容。
4〕numberinput()
函数原型:
floatnumberinput(char*notice)
numberinput()函数用于输入数值型数据,notice用于保存printf()中输出的提示消息。
5〕Stringinput()
函数原型:
voidStringinput(char*t,intlens,char*notice)
164
Stringinput()函数用于输入字符串,并进行字符串长度验证〔长度6)Locate()
函数原型:
intLocate(ZGGZtp[],intn,charfindmess[],charnameornum[[])
Locate()函数用于定位数组重符合要求的元素,并返回该数组元素下标值。
参数findmess[]保存要查找的具体内容,nameornum[]保存按什么字段在数组tp中查找。
7)Add()
函数原型:
intAdd(ZGGZtp[],intn)
Add()函数用于在数组tp中增加工资记录元素,并返回数组中的当前记录。
并显示出来。
8)Qur()
函数原型:
voidQur(ZGGZtp[],intn)
Qur()函数用于在数组tp中按职工编号或查找满足条件的记录,并显示出来。
9)Del()
函数原型:
intDel(ZGGZtp[],intn)
Del()函数用于现在数组tp中找到满足条件的记录,然后删除记录。
10)Modify()
函数原型:
voidModify(ZGGZtp],intn)
Modify函数用于在数组tp中修改记录元素。
11)Inser()
函数原型:
Insert(ZGGZtp[]intn)
Insert函数用于在数组tp中插入记录,并返回数组中的当前记录数。
12)Tongji()
函数原型:
voidTongji(ZGGZtp[]intn)
Tongji()函数用于在数组tp中完成记录的统计工作,统计该公司职工工资的整体分布情况。
13)Sort()
函数原型:
voidSort(ZGGZtp[],intn)
Sort()函数用于在数组tp中完成利用冒泡排序算法实现数组的按实发工资字段的降序排序。
14)Save()
函数原型:
voidSave(ZGGZtp[]intn)
Save()函数用于将保存职工工资的数组tp中的n个元素写入磁盘的数据文件中。
15)主函数main()
main()是整个工资管理系统控制部分。
7.4程序实现
7.4.1源码分析
包括加载头文件,定义结构体,常量和变量,并对它们进行初始化工作。
#include"stdio.h"/*标准输入输出函数库*/
#include"stdlib.h"/*标准函数库*/
#include"string.h"/*字符串函数库*/
#include"conio.h"/*屏幕操作函数库*/
#defineHEADER1"-------------------------------ZGGZ----------------------------------------\n"
#defineHEADER2"|number|name|jbgz|jj|kk|yfgz|sk|sfgz|\n"
#defineHEADER3"|--------|-----------|--------|--------|--------|--------|--------|--------|\n"
#defineFORMAT"|%-8s|%-10s|%8.2f|%8.2f|%8.2f|%8.2f|%8.2f|%8.2f|\n"
#defineDATAp->num,p->name,p->jbgz,p->jj,p->kk,p->yfgz,p->sk,p->sfgz
#defineEND"----------------------------------------------------------------------------\n"
#defineN60
intsaveflag=0;/*是否需要存盘的标志变量*/
/*定义与职工有关的数据结构*/
typedefstructemployee/*标记为employee*/
{
charnum[10];/*职工编号*/
charname[15];/*职工*/
floatjbgz;/*基本工资*/
floatjj;/*奖金*/
floatkk;/*扣款*/
floatyfgz;/*应发工资*/
floatsk;/*税款*/
floatsfgz;/*实发工资*/
}ZGGZ;
2.主函数main()
main()函数主要实现了对整个程序的运行控制,以及相关功能模块的调用。
详细分析可参考图7.2。
voidmain()
{
ZGGZgz[N];/*定义ZGGZ结构体*/
FILE*fp;/*文件指针*/
intselect;/*保存选择结果变量*/
charch;/*保存(y,Y,n,N)*/
intcount=0;/*保存文件中的记录条数〔或元素个数〕*/
fp=fopen("C:
\\zggz","ab+");
/*以追加方式打开二进制文件c:
\zggz,可读可写,假设此文件不存在,会创建此文件*/
if(fp==NULL)
{
printf("\n=====>cannotopenfile!
\n");
exit(0);
}
while(!
feof(fp))
{
if(fread(&gz[count],sizeof(ZGGZ),1,fp)==1)/*一次从文件中读取一条职工工资记录*/
count++;
}
fclose(fp);/*关闭文件*/
printf("\n==>openfilesucess,thetotalrecordsnumberis:
%d.\n",count);
getchar();
menu();
while
(1)
{
system("cls");
menu();
printf("\nPleaseEnteryourchoice(0~9):
");/*显示提示信息*/
scanf("%d",&select);
if(select==0)
{
if(saveflag==1)/*假设对数组的数据有修改且未进行存盘操作,则此标志为1*/
{getchar();
printf("\n==>Whethersavethemodifiedrecordtofile?
(y/n):
");
scanf("%c",&ch);
if(ch=='y'||ch=='Y')
Save(gz,count);
}
printf("\n===>thankyouforuseness!
");
getchar();
break;
}
switch(select)
{
case1:
count=Add(gz,count);break;/*增加职工工资记录*/
case2:
count=Del(gz,count);break;/*删除职工工资记录*/
case3:
Qur(gz,count);break;/*查询职工工资记录*/
case4:
Modify(gz,count);break;/*修改职工工资记录*/
case5:
count=Insert(gz,count);break;/*插入职工工资记录*/
case6:
Tongji(gz,count);break;/*统计职工工资记录*/
case7:
Sort(gz,count);break;/*排序职工工资记录*/
case8:
Save(gz,count);break;/*保存职工工资记录*/
case9:
system("cls");Disp(gz,count);break;/*显示职工工资记录*/
default:
Wrong();getchar();break;/*按键有误,必须为数值0-9*/
}
}
}
用户进入工资管理系统时,需要显示主菜单,提示用户进行选择,完成相应任务。
此代码被main()函数调用。
voidmenu()/*主菜单*/
{
system("cls");/*调用DOS命令,清屏.与clrscr()功能相同*/
textcolor(10);/*在文本模式中选择新的字符颜色*/
gotoxy(10,5);/*在文本窗口中设置光标*/
cprintf("TheEmployee'SalaryManagementSystem\n");
gotoxy(10,8);
cprintf("*************************Menu********************************\n");
gotoxy(10,9);
cprintf("*1inputrecord2deleterecord*\n");
gotoxy(10,10);
cprintf("*3searchrecord4modifyrecord*\n");
gotoxy(10,11);
cprintf("*5insertrecord6countrecord*\n");
gotoxy(10,12);
cprintf("*7sortreord8saverecord*\n");
gotoxy(10,13);
cprintf("*9displayrecord0quitsystem*\n");
gotoxy(10,14);
cprintf("*************************************************************\n");
/*cprintf()送格式化输出至文本窗口屏幕中*/
}
由于记录显示操作经常进行,所以我们将这部分由独立的函数来实现,以减少代码的重复。
过程如下。
(1)调用Disp(ZGGZtp[],intn)函数,它将显示从数组tp第一个元素开始的n条
记录。
(2)调用printdata(ZGGZpp)函数,它将显示数组元素pp中的记录信息。
voidprintheader()/*格式化输出表头*/
{
printf(HEADER1);
printf(HEADER2);
printf(HEADER3);
}
voidprintdata(ZGGZpp)/*格式化输出表中数据*/
{
ZGGZ*p;
p=&pp;
printf(FORMAT,DATA);
}
voidDisp(ZGGZtp[],intn)/*显示数组tp[]中存储的记录,内容为employee结构中定义的内容*/
{
inti;
if(n==0)/*表示没有职工工资记录*/
{
printf("\n=====>Notemployeerecord!
\n");
getchar();
return;
}
printf("\n\n");
printheader();/*输出表格头部*/
i=0;
while(i{
printdata(tp[i]);
i++;
printf(HEADER3);
}
getchar();
}
voidWrong()/*输出按键错误信息*/
{
printf("\n\n\n\n\n***********Error:
inputhaswrong!
pressanykeytocontinue**********\n");
getchar();
}
voidNofind()/*输出未查找此职工的信息*/
{
printf("\n=====>Notfindthisemployeerecord!
\n");
}
用户进入工资管理系统时,在对某个记录进行处理前,需要按照条件找到这条记录,Locate()函数完成了记录定位的功能。
这里可以按照职工编号或职工进行记录查找定位。
/*************************************************************
作用:
用于定位数组中符合要求的记录,并返回保存该记录的数组元素下标值
参数:
findmess[]保存要查找的具体内容;nameornum[]保存按什么在数组中查找;
**************************************************************/
intLocate(ZGGZtp[],intn,charfindmess[],charnameornum[])
{
inti=0;
if(strcmp(nameornum,"num")==0)/*按职工编号查询*/
{
while(i{
if(strcmp(tp[i].num,findmess)==0)/*假设找到findmess值的职工编号*/
returni;
i++;
}
}
elseif(strcmp(nameornum,"name")=