1、C语言实践应用 人事管理管理系统 [要求] 某高校主要人员有:在职人员(行政人员、教师、一般员工)、退休人员和临时工。现在,需要存储这些人员的人事档案信息:编号、姓名、性别、年龄、职务、职称、政治面貌、最高学历、任职时间、来院时间、人员类别。其中,人员编号唯一,不能重复。 (1) 添加删除功能:能根据学院人事的变动情况,添加删除记录; (2) 查询功能:能根据编号和姓名进行查询; (3) 编辑功能(高级):根据查询对相应的记录进行修改,并存储; (4) 统计功能:能根据多种参数进行人员的统计(在职人数、党员人数、女工人数、高学历高职称人数(硕士学位以上或者副教授以上)),统计
2、要求同时显示被统计者的信息; (5) 排序功能:按照年龄、来院时间进行排序; (6) 保存功能:能对输入的数据进行相应的存储; 一、 需求分析: 根据题目要求,职工信息是存放在文件中的,所以应该提供相应的文件的输入输出的功能,在程序中应该有添加删除,查询,编辑,统计,排序,保存等程序实现相应的操作,另外菜单式的选择方式选择程序的功能也是必须需的。另外程序中要求存储的模块,采用的方式均为将原文件中的所有数据读入内存,在内存中处理之后以覆盖的方式写入文件中重新储存,这样的方法容易理解、容易编写,但当文件中的数据量很大时,这种方法也存在一定的难度,在本程序中将N定为100,也即最多可储存
3、的职工人数为100; 二、 总体设计: 根据以上需求分析,将程序分成以下几个模块: 1、 新建档案信息; 2、 删除信息; 3、 追加信息; 4、 搜索查找信息(按姓名或者编号搜索); 5、 浏览全部信息; 6、 修改信息; 7、 信息排序; 8、 信息统计; 三、 详细设计; 1、 主函数: 〈1〉需求分析: 为使系统执行完每部分功能后能够方便的回到系统主界面,main()函数设计的很简单,只包含一个menu()函数,其余的全部功能都通过menu()函数调用来实现,并通过menu()函数的递归调用实现返回主界面的功能。 main()函数定义如下: ma
4、in() {menu();} 而menu()定义如下: 〈2〉流程图: void menu() { int n,w1; do { printf("\n\t\t\t\t菜\t单\n"); printf("\n\t\t0\t新建档案信息\n\n"); printf("\t\t1\t删除信息\n\n"); printf("\t\t2\t追加信息\n\n"); printf("\t\t3\t搜索查找信息\n\n"); printf("\t\t4\t浏览所有信息\n
5、\n"); printf("\t\t5\t修改信息\n\n"); printf("\t\t6\t信息排序\n\n"); printf("\t\t7\t信息统计\n\n"); printf("\t\t8\t离开\n\n"); printf("\t\t请选择您要进行的操作 [ ]\b\b"); /**显示一系列功能并提示选择**/ scanf("%d",&n); if(n<0||n>8) { w1=1; getchar();
6、 } else w1=0; } while(w1==1); /**输入n并判断是否属于0到8**/ switch(n) { case 0:build();break; case 1:del();break; case 2:add();break; case 3:search();break; case 4:browse();break; case 5:modify();break; case 6:o
7、rder();break; case 7:data();break; case 8:exit(0); default:{printf("输入错误!请重新输入");menu();} /**根据n的值调用各功能函数**/ } } 2、各功能模块设计: (1)、新建档案信息模块: <1>、数据结构; 看各个数据信息,编号、姓名、性别、年龄、职务、职称、政治面貌、最高学历、任职时间、来院时间、人员类别,均为字符串类型,在文件中以文本形式存放,每条记录对应一个人员的信息,可以方便信息的管理;而数据读进内存中时,可以以结构体的形式,每一个结构体包含了一个人员
8、的全部信息,多的人员的信息组成了一个结构体数组。定义如下: struct worker {char num[11]; char name[10]; char sex[2]; char age[3]; char zhiwu[15]; char zhicheng[15]; char zhengzhi[15]; char xueli[15]; char renzhisj[8]; char laiyansj[8]; char leibie[15]; }wk[N],s; 其中N是宏定义形式定义的字符,临时定
9、义为100,wk[N],为存放人员信息的结构体数组,而S为临时的结构体,用来保存信息处理过程中的临时数据。 〈2〉、流程图如下: 〈3〉、程序: int build() { int i,m,n,p; FILE *fp; if((fp=fopen("worker00.txt","w"))==NULL) { printf("can not build file\n"); printf_back(); /*输入用户要输入的学生的个数N*/ } printf("您要输入的人
10、数是(0-%d)?:",N);
scanf("%d",&m);
n=m;
for(i=0;i 11、wk[p].sex,wk[p].age,wk[p].zhiwu,wk[p]. zhicheng,wk[p].zhengzhi,wk[p].xueli,wk[p].renzhisj,wk[p].laiyansj,wk[p].leibie))!=1)
printf("cannot write the data\n\n"); /*将结构体数组中的数据写入文件*/
fclose(fp); /*关闭文件*/
printf_back();
}
(2)、追加 12、模块:
〈1〉[需求分析]
该模块的功能是拥护需要增加新的员工记录,从键盘输入并逐条写入到原来的文件中去,其中输入号码是要防止号码重复,重复时报告错误,重新输入。为方便用户管理和查看,该模块采用的方式是用先把原来文件中的数据读入内存,保存在内存中,然后在内存中的数据后面增加新的数据,操作完成后用写的方式打开文件,用覆盖的方式写入。
〈2〉流程图:
〈3〉程序:
int add()
{
int i,m,n,p;
FILE *fp;
n=load(); /*调用加载函 13、数load将文件中的数据读入内存*/
if(n==-1)
{
printf("\n对不起,还没有档案,请新建一个档案\n");
menu();
}
printf("您要追加的人数是(0-%d)?:[ ]\b\b\b",N-n);
scanf("%d",&m); /*输入要追加的人员个数m*/
for(i=n+1;i<=m+n;i++)
{
printf("\n追加第%d个工作人员的信息\n",i-n);
input(i); 14、 /*从n到k调用输入函数input(i)*/
}
if((fp=fopen("worker00.txt","a+"))==NULL)
{
printf("can not open file\n");
printf_back(); /*调用*/
}
for(p=n+1;p<=m+n;p++) fprintf(fp,"%s\t%s\t%1s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",wk[p].num,wk[p].name,wk[p].sex,wk[p].age,wk[p].zhiwu,wk[p] 15、 zhicheng,wk[p].zhengzhi,wk[p].xueli,wk[p].renzhisj,wk[p].laiyansj,wk[p].leibie);
/*从0到k以覆盖的方式写入文件并保存*/
fclose(fp);
printf_back(); /*关闭文件*/
}(3)修改模块:
〈1〉 [需求分析:]
该模块的功能是显示所有信息,考虑到记录较多,采用分屏显示,显示完所有的记录后,由用户输入需要修改的人员的号码,查找成功后,显示查找结果,并询问拥护修改人员的哪部分记录,根据用户选择修改相应的信息,然后保存修改后的结 16、果;
〈2〉 流程图
〈3〉 程序;
modify()
{
int i,n,k,p,w0=1,w1,w2=0;
FILE *fp;
n=load();
do
{
k=-1;
printf_face();
for(i=0;i<=n;i++) printf_one(i);
do
{
printf("\n\n请输入你要修改的信息的编号\n\t\t编号:[ ]\b\b");
scanf("%s",s.num);
for(i= 17、0;i<=n;i++)
{
if(strcmp(s.num,wk[i].num)==0)
{
k=i;
s=wk[i];
}
}
if(k==-1) printf("\n\n没有找到您所需的信息 ! 请重新输入!\n");
}while(k==-1);
printf_face();
printf_one(k);
w1=modify_data(k);
if(w1==1)
{
printf("\n修改成功!\n\n要继续修 18、改吗?\n\n\t\t1\t是\n\n\t\t2\t保存并返回\n\t[ ]\b\b");
scanf("%d",&w0);
w2=1;
}
else
{
w0=0;
if(w2==1)
wk[k]=s;
}
if(w0!=1&&w2==1)
{
fp=fopen("worker00.txt","w");
{
for(p=0;p<=n;p++)
fprintf(fp, 19、"%s\t%s\t%1s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",wk[p].num,wk[p].name,wk[p].sex,wk[p].age,wk[p].zhiwu,wk[p]. zhicheng,wk[p].zhengzhi,wk[p].xueli,wk[p].renzhisj,wk[p].laiyansj,wk[p].leibie);
}
fclose(fp);
}
}while(w0==1);
menu();
}
修改数据函数如下:
modify_data(int i)
{
20、 int c,w1;
do
{
printf("\n请选择需要修改的项=>\n\n\t\t1\t编号\n\t\t2\t姓名\n\t\t3\t性别\n\t\t4\t年龄\n\t\t5\t职务\n\t\t6\t职称\n\t\t7\t政治面貌\n\t\t8\t学历\n\t\t9\t任职时间\n\t\t10\t来院时间\n\t\t11\t在职类别\n\n\t\t\t[ ]\b\b");
scanf("%d",&c);
if(c>11||c<1) printf("错误,请重新选择!");
getchar();
}while( 21、c>11||c<1);
do
{
switch(c)
{
case 1:printf("旧的编号是 %s,",wk[i].num);input_num(i,i-1);break;
case 2:printf("旧的姓名是 %s,请输入新的姓名:",wk[i].name);scanf("%s",wk[i].name);break;
case 3:printf("旧的性别是 %s,请输入新的性别:",wk[i].sex);scanf("%1s",wk[i].sex);break;
case 4:printf("旧 22、的年龄是 %s,请输入新的年龄:",wk[i].age);scanf("%s",wk[i].age);break;
case 5:printf("旧的职务是 %s,请输入新的职务:",wk[i].zhiwu);scanf("%s",wk[i].zhiwu);break;
case 6:printf("旧的职称是 %s,请输入新的职称:",wk[i].zhicheng);scanf("%s",wk[i].zhicheng);break;
case 7:printf("旧的政治面貌是 %s,请输入新的政治面貌:",wk[i].zhengzhi) 23、scanf("%s",wk[i].zhengzhi);break;
case 8:printf("旧的学历是 %s,请输入新的学历:",wk[i].xueli);scanf("%s",wk[i].xueli);break;
case 9:printf("旧的任职时间是 %s,请输入新的任职时间:",wk[i].renzhisj);scanf("%s",wk[i].renzhisj);break;
case 10:printf("旧的来院时间是 %s,请输入新的来院时间:",wk[i].laiyansj);scanf("%s",wk[i]. 24、laiyansj);break;
case 11:printf("旧的在职类别是 %s,请输入新的在职类别:",wk[i].leibie);scanf("%s",wk[i].leibie);break;
}
printf("now:\n\n");
printf_face();
printf_one(i);
printf("\n确定修改吗?\n\n\t\t1\t是\n\t\t2\t重新修改\n\t\t3\t返回并不保存\n\t\t\t[ ]\b\b\b");
scanf("%d",&w1); 25、
}while(w1==2);
return(w1);
}
(4)删除模块:
〈1〉[需求分析]:
该模块的运行方式与修改模块类似,首先分屏显示所有人员的记录,显示完所有的记录后,由用户输入要删除的人员的号码,根据号码查找相应的记录并将结果显示出来,经用户确认后删除,删除的方法是将文件中的数据读入内存,赋给相应的结构体,并将结构体数组中将删除的后面的数据赋给前一个结构体,然后将相应数据写入文件并保存;
〈2〉流程图:
Y
〈3〉程序;
int del()
{
char c;
int i,j,n,k,m,w0,w1=0,w2=0;
FILE 26、fpt; /*fpt?*/
n=load();
do
{
k=-1;
printf_face(); /*调用*/
for(i=0;i<=n;i++) printf_one(i);
do
{
printf("\n\n请输入您想要删除的人员的编号!\n\t\tNO.[ ]\b\b");
scanf("%s",s.num);
for(i=0;i<=n;i++)
if(strcmp 27、s.num,wk[i].num)==0);
{
k=i;
s=wk[i];
}
if(k==-1)
printf("\n\n对不起,这个编号不存在! 请重新输入");
}
while(k==-1);
printf("确定要删除吗? \t请输入y或者n\n\t\t[ ]\b\b");
scanf("%1s",&c);
if(c=='y')
{
for(j=i;j<=n;j++) wk[j]=wk[j+1] 28、
w1=1;
}
if(c=='n') menu();
else
{
printf("\n错误,请输入y或者n\n");
menu();
}
if(w1==1)
{
printf("\n删除成功!\n\n您要继续删除吗?\n\n\t\t1\t是\n\n\t\t2\t保存并返回\n\t[]\b\b");
scanf("%d",&w0);
w2=1;
}
if(w0==2&&w2==1)
{
fpt=fopen("w 29、orker00.txt","w");
for(m=0;m<=n;m++)
fprintf(fpt,"%s\t%s\t%1s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",wk[m].num,wk[m].name,wk[m].sex,wk[m].age,wk[m].zhiwu,wk[m]. zhicheng,wk[m].zhengzhi,wk[m].xueli,wk[m].renzhisj,wk[m].laiyansj,wk[m].leibie);
fclose(fpt);
}
}
30、 while(w0==1);
menu();
}(5)、按号码搜索:
〈1〉[需求分析]:
该模块的功能是按照输入的人员的号码查找对应的记录,并将其显示,查找成功以后,增加删除和修改等功能,其中删除和修改功能可以通过调用相应的函数来实现。
〈2〉流程图;
〈3〉、程序;
snum()
{
FILE *fp;
int i,k,w1=1,w2,w3,n;
n=load();
do
{
do
{
k=-1;
printf("\n\n请输 31、入您要查询的编号!\n\t\tnumber:[ ]\b\b\b\b\b");
scanf("%s",s.num);
for(i=0;i<=n;i++)
if(strcmp(s.num,wk[i].num)==0)
{
k=i;
printf_one(k);
break;
}
if(k==-1)
{
printf("\n\n您查询的编号不存在!请重新输入");
pri 32、ntf("\n\n您要继续查询吗?\n\t\t1\t继续\n\t\t2\t返回\n\t\t[ ]\b\b");
scanf("%d",&w1);
if(w1==2)
{
menu();
break;
}
if(w1!=1&&w1!=2)
{
printf("\n对不起,请输入 1 或 2 \n");
printf("\n请重新输入\n");
}
}
}while(k==-1&&w1! 33、2);
if(k!=-1)
{
w3=0;
printf("\n要继续查询吗?\n\t\t1\t继续\n\t\t2\t返回菜单\n\t\t[ ]\b\b");
scanf("%d",&w3);
if(w3==2)
{
menu();
break;
}
if(w3!=1&&w3!=2)
{
printf("\n对不起,请输入 1 或 2 \n");
search();
break;
}
}
}wh 34、ile(k!=-1&&w3==1);
}(6)按姓名搜索。
该模块的结构与按号码查询的结构基本相同;
(7) 浏览模块;
〈1〉 需求分析:
该模块的功能是显示所有保存在文件中的记录,考虑到记录较多,采用分屏显示的方式;
〈2〉、流程图;
〈3〉程序:
browse()
{
int i,j,n;
n=load(); /*调load函数将所有的数据调入内存*/
printf_face(); /*调用表头函数*/
for(i=0;i<=n;i++) printf_one(i) 35、
printf("\t总计有%d个工作人员\n",n+1);
printf("按任意键继续...");
getch();
menu();
}
(9)、排序模块;
〈1〉、[需求分析];
该模块的功能是要求将记录按照年龄或者来院时间进行排序,总体结构是先用n=load()函数将文件中的数据调入内存,然后按照选择法排序,并将结果显示出来,然后将排序后的结果保存。
〈2〉 流程图;
〈3〉 程序;
order()
{
int i,j,k,n,p;
FILE *fp;
n=load();
print 36、f("请选择您要排序的项\n\t\t1\t年龄\n\t\t2\t来院时间\n\n");
scanf("%d",&p);
if(p==1)
{
for(i=0;i<=n-1;i++)
{
for(j=i+1;j<=n;j++)
{
if(strcmp(wk[i].age,wk[j].age)<0)
{
s=wk[i];
wk[i]=wk[j];
wk[j]=s;
}
}
37、}
}
for(k=0;k<=n;k++) printf_one(k);
if(p==2)
{
for(i=0;i<=n-1;i++)
{
for(j=i+1;j<=n;j++)
{
if(strcmp(wk[i].laiyansj,wk[j].laiyansj)<0)
{
s=wk[i];
wk[i]=wk[j];
wk[j]=s;
}
}
}
}
for(k=0;k<=n;k++) printf_on 38、e(k);
printf("\n按任意键返回菜单:[]\n");
scanf("%s",&p);
if(!p||p)
menu();
}(10)、统计模块
〈1〉、[需求分析];
该模块的功能是按照用户的要求统计出满足符合条件的所有记录的个数,并将满足条件的记录显示出来。该模块没有涉及到文件的保存,所以将文件用只读的方式打开,可以防止操作过程中数据的丢失。
〈2〉流程图;
〈3〉、程序
data()
{
int p,w;
printf("请选择您要统计的项目?\n\t\t1\t在职人数\n\t\t2\t党员人数\n\t\t3\t女工人数 39、\n\t\t4\t高学历人员统计\n\t\t5\texit\n\n\t\t[ ]\b\b");
scanf("%d",&p);
switch(p)
{
case 1:numduty();break;
case 2:numpm();break;
case 3:numwm();break;
case 4:hiedcation();break;
case 5:menu();break;
default:
{
printf("错误,请输入一个1~4之间的数字!");
data();
}
}
40、
printf("\n您要继续统计吗?继续请按 1 ,返回菜单请按 2 \n");
scanf("%d",&w);
if(w==1) data();
if(w==2) menu();
if(w!=1&&w!=2) menu();
}}
该过程中调用了四个函数,numduty()(统计在职人员人数),numpm()(统计党员人数),numwm()(统计女工人数),hieduction()(统计高学历高职称人数),函数的具体定义见后面附录源程序。
并通过在四个函数中调用menu()函数返回到主菜单。
上机操作:
1:数据源
2:编译,连接和运行
下面是各个模块的运行结果的界面图:
1、 主菜单函数界面:
2、输入模块:
3、删除模块:
4、浏览模块;
5、编辑模块:
6、统计模块:
7、排序模块:
8、搜索模块






