资源描述
目录
一、需求分析-------------------------------------1
二、概要设计-------------------------------------2
三、详细设计-------------------------------------3
四、调试分析-------------------------------------9
五、数据测试------------------------------------10
六、课设总结------------------------------------13
七、程序代码------------------------------------15
一、需求分析
1、设计目的
1、设计一个ubuntu下的工资管理系统
2、掌握基于Linux环境用C语言定义单链表结构以及实现文件操作:
(1) 实现链表的创建、查询、插入、删除等基本操作;
(2) 实现文件内容读取到链表和将链表内容写入文件的操作。
2、 设计内容
1、创建链表,录入数据。
2、数据的读写操作。
3、数据的更新操作。
4、数据的删除和插入。
5、请你要求对数据进行查找。
6、按要求统计工资信息。
7、设计总体菜单界面。
3、 设计内容
1、录入数据
职工的基本信息,包括工号、姓名、身份证号、籍贯、部门、职务、基本工资、岗位工资、基金、税金、奖金、应发工资、实发工资等。
2、数据存储
信息的录入要求用链表,然后把链表存入指定文件中,并把每次录入的信息以追加方式添加到数据文件尾,以便随时查看,也可供程序调用,方便操作人员不用重复输入数据。
3、数据的更新
更新包括插入、删除、修改。因为工号是唯一区分不同职工的属性,故删除根据学号删除,如需要删除所有信息只需直接删除数据文件即可。
4、数据的查询
查询可以根据工号号和姓名不同方面进行查询,方便操作者使用。
5、数据的统计
操作者可以根据系统的数据统计出全公司或者各部门的平均工资、最低工资、最高工资、工资方差。
4、 设计细节
1、多职工信息进行操作时,建立动态链表,每个节点包含一个职员的工号、姓名、工资等全部信息,通过链表构建一个完整的职工信息库,链表具备录入、删除、修改、查询及统计功能,各功能显示在菜单中,由主函数分别调用。
2、为了避免一个函数体过长,进行细化子函数,小型子函数在各个主调函数里多次调用,便于使用。
3、以可读可写可追加方式新建一个文本文件,用于存储链表里所有节点上包含的信息,将节点信息导入文件时,从头指针开始,依次写入。
4、查询、修改、删除、职工信息时,调用子函数以只读方式打开系统库文件,并将文件从头至尾读取一遍,每次读取一个节点的长度,将每次读取到的信息依次导入到链表的节点中去,再对链表进行所需功能的操作。修改和删除完成后,将整个链表包含的信息重新写入文件,写入之前打开系统库文件同时进行格式化。
5、统计职工最高、最低工资及工资均方差时,以同时方式将职工工资等信息导入到链表中,然后以子菜单的形式输出统计的项目,包括各部门和全公司以及最高、最低工资和工资均方差。统计各部门最高、最低工资和工资均方差时需再调用子函数分别进行操作。统计全公司最高、最低工资和工资均方差时采用多分支结构进行。
6、菜单及所有操作提示信息均采用中文输出,每一步操作后会有相应的提示。如文件不存在或为空时,会提示“文件打开失败!”或“文件是空的!”或输入有误时提示重新输入。
二、概要设计
1、系统结构图
主函数
录入存储
数据操作
输出信息
输入
统计
查找
修改
删除
显示
2、 流程控制
int main(){
do{
函数分支:1)录入记录:创建链表函数后以追加方式将链表写入数据文件,如无文件则新建;
2)删除记录:调用读取职工工资信息文件函数和修改链表函数后重新写入文件;
3)查询记录:调用读取职工工资信息文件函数和输出所查节点信息函数;
4)修改记录:调用读取职工工资信息文件函数和修改信息函数后重新写入文件;
5)统计记录:先调用读取职工工资信息文件函数,然后采用两层多分支结构,第一层进行部门选择,第二层调用统计最低、最高、平均工资和工资方差函数,统计全公司工资时直接对信息链表查找和计算;
0)退出系统:exit(0);
}while(退出系统:exit(0))
3、 功能模块说明
(1) 数据录入:创建单链表,调用初始化函数申请头结点,采用头插法创建链表完成后,以追加方式打开数据文件并将信息添加到文件中;
(2) 删除模块:先将文件信息读出存到链表中,提示输入工号,若找到信息可以将工号对应的职工记录删除;
(3) 修改模块:先将文件信息读出存到链表中,提示输入工号,然后提示选择修改项目,若找到信息可修改对应职工记录的某项信息;
(4) 查询模块:先将文件信息读出存到链表中,提示输出所有记录还是按条件详细查询,若选择前者调用读取文件函数后依次输出所有信息,若选择后者提示输入工号或者姓名,若找到信息将输出工号对应的职工记录;
(5) 统计模块:先将文件信息读出存到链表中,提示输入统计要求,再调用统计子函数,若找到信息则输出统计结果。
三、详细设计
1、函数设计
void menu_ad(); /*菜单*/
void Write_to_File(st_em_sal *L); /*将信息写入文件*/
void Read_from_File(st_em_sal *h); /*读出文件信息*/
int print_inf(); /*显示文件信息信息*/
void InitSt_em_sal(st_em_sal **h); /*创建头结点*/
void create_list(); /*创建链表函数*/
void search(); /*查询记录函数*/
void search_by(st_em_sal *head); /*按条件查询记录*/
void modify(); /*修改记录函数*/
void delete(); /*删除记录函数*/
void count_sal(); /*声明统计函数*/
void count_choose(st_em_sal *head,char department[]);/*统计中的选择函数*/
void count_min_s(st_em_sal *head,char department[]);/*计算最低工资函数*/
void count_max_s(st_em_sal *head,char department[]);/*计算最高工资函数*/
void count_avr_s(st_em_sal *head,char department[]);/*计算平均工资函数*/
void count_var_s(st_em_sal *head,char department[]);/*计算工资方差函数*/
2、 功能模块设计
(1)录入模块
开始
创建职工记录链表
输入插入的学生信息
链表头插入学生信息
继续录入?
是
否
以追加方式将信息录入数据文件
结束
(2) 查找模块
开始
将文件中职工记录读到链表中
输入要查找的职工工号stu_num
组织循环,扫描存储职工信息的链表
p->stu_num==stu_num?
否
否
是
P==NULL?
输出该职工的信息
否
无对应信息!
结束
(3) 修改模块
开始
将文件中职工记录读到链表中
输入要修改的职工工号stu_num
组织循环,扫描存储职工信息的链表表
p->stu_num==stu_num?
否
否
P==NULL?
是
选择修改项
是
无对应信息!
修改学生信息
将链表重新写入数据文件中
结束
(4)删除模块
开始
将文件中职工记录读到链表中
输入要删除职工工号stu_num
组织循环,扫描存储职工信息的链表
p->stu_num==stu_num?
否
否 是
P==NULL?
删除该职工信息
是
将链表重新写入数据文件中
结束
(5)统计模块
开始
将文件中职工记录读到链表中
选择统计范围
选择统计项目
组织循环,扫描存储学生信息的链表表
调用子函数统计职工记录
找到信息?
是
输出统计结果
没有记录!
结束
四、调试分析
1、开始创建了链表之后,将整个链表中的信息写入文件时,写入方式不对,导致总是出现写入和读写错误,最终向文件里写入数据块内容时,选择了fprintf的方式,以追加方式循环写入,每次写入一条记录。
2、修改和删除后文件里的数据出现错乱,再次查询时出现乱码,原因还是操作后的写入方式不对,需要以“wb”方式将原文件清空再将整个链表中的信息写入。
3、进行工资信息统计时,输出结果有错误,加入员工数的输出后发现输出的员工数比录入的多,且其工资为0的情况,进行查询函数检验时发现会输出多余的空信息(无职工名、无工号、工资为零等)或者重复输出,原因应该是存入文件时存在问题,因此在输出查询信息及统计时加入了限制条件将空节点或者多余的信息筛选掉。
4、统计分为各部门和全公司,如果只用一个子函数实现所有统计功能则比较繁琐、函数体太大,因此需再使用子函数分别对各项目进行统计,那么进行不同部门的统计时调用子函数就比较困难。因此在这些统计最低工资、最高工资、平均工资、工资方差的函数中,需要定义一个部门变量,在条件语句里把部门信息通过参数传递在子函数中使用,从而通过条件语句找到该部门信息并统计。
5、在查询函数中,为了避免繁琐,同样调用子函数对链表进行操作,在进行修改方式和删除方式选择时,需要重新定义一个共同变量并传递给子函数,在判断语句里采用“或”语句对姓名和工号同时搜索。
6、在进行职工信息添加时,开始没有避免重复信息的输入,输入已有的职工工号时,应提示“已有该职工信息!”,因此要对原文件的内容进行便利检索,同时要对正在建立的链表进行检索,因为无法将原文件内容与正在建立的链表连接起来,只能通过对两个链表进行两次检索,将正在建立的链表以追加的方式写到已经建立好的文件中(添加到原数据后面)。
7、进行菜单内的操作提示输入有误时,再按任意键会直接退到主菜单,再要进行该操作需重新选择菜单,耗费时间,使用循环语句控制,提示“输入有误时!”再次提示输入,将新输入的数据重新赋给变量,知道输入信息正确时,包括部门及职务的合法性检验。
8、将职工的基金、税金、应发工资等信息修改后,输出查询的各项结果除以修改的其他的不变,那么就不符合要求,因为应发工资等于基本工资与岗位工资、奖金之和,实发工资等于应发工资减去基金和税金,因此修改这些信息时,需要重新计算,保证各项信息正确。
五、数据测试
1、系统主菜单
2、录入工资记录
3、输出全部工资记录
4、按条件(姓名或工号)查询工资记录
5、删除工资记录
6、修改工资记录
6、统计工资记录
六、 课设总结
1、学习记录
为了更好地深入学习Linux的相关知识,也便于课设过程中的开发,在这个 阶段内我学习了很多开发知识,以及便于开发的技巧,包括以下几个方面:
(1) GNU开发环境基础,包括gcc编译、gdb调试、Makefile;
(2) Linux C语言库函数和头文件;
(3) Linux远程连接及访问、文件共享、Samba服务器配置;
(4) MySQL的安装及管理、MySQL的基本功能以及通过从语言程序访问MySQL数据库的API;
(5) 使用curses函数库管理基于文本的屏幕。
2、 学习方式及心得体会
我借助于课本上的介绍和例程以及通过网络上下载的文档及视频资源来学习,在学习的过程中,先看懂使用方法及例程,然后自己也按照方法或例程试着调试和更改程序得到自己想要的结果。虽然最终没有完成目标,没有达到用curses和数据库的结果,但是为我以后学习相关知识打下了基础,也使我认识到自己的不足,如怎么合理安排课设计划、如何高效地学习到所需要的知识。在这个过程中,因为时间有限所做的课设成果没有令自己满意,尽管如此,我明白了更重要的是学习到了更多的方法和技巧。知识积累和运用是一个合理学习加缓慢进步的过程,通过这次课设我也发现了自己的兴趣,知道以后该如何积累相关知识并多多实践。解决困难的过程中,再次锻炼了我独立解决问题的能力,更加培养了自己的钻研精神,也使得知识更全面看问题更细致。解决实际的开发问题时,一步步的去调试,这也是我这次课设收获的一个经验。
最终这次课设我所有内容还是用的C语言来完成,但这也让我重新回顾了一下语言知识,特别是指针和文件的内容,再结合在Linux上开发的一些不同点,我更加深入地得到了学习,使我C语言掌握得更牢固,以便为以后嵌入式的学习工作打下了基础。总之这次课设仍旧让我受益匪浅。
显然,这个管理系统还有许多需要改进的地方,后期将会结合所学知识对其进行完善,以提高自己的设计开发与学习能力,如利用curses函数库完善界面等,下面使用curses函数库完成的部分效果:
3、参考资料
(1)Linux程序设计(课本);
(2)Linux从入门到精通第二版;
(3)Linux入门(视频资料);
(4)Linux系统开发(视频资料);
七、程序代码
1、 Makefile文件
myapp:salary_system.o
gcc -o myapp salary_system.o
salary_system.o:salary_system.c
gcc -c salary_system.c
2、 源程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef struct employee_salary
{
char stu_num[20]; /*职工工号*/
char card_id[20]; /*身份证号*/
char name[20]; /*姓名*/
char department[20]; /*部门*/
char position[20]; /*职位*/
char bir_pla[20]; /*籍贯*/
long int bas_sal; /*基本工资*/
long int fund; /*基金*/
long int der_sal; /*应发工资*/
long int tax; /*税金*/
long int bonus; /*奖金*/
long int act_sal; /*实发工资*/
long int pos_sal; /*岗位工资*/
struct employee_salary *next; /*指向下一节点的指针*/
}st_em_sal;
void menu_ad(); /*管理员菜单*/
void Write_to_File(st_em_sal *L); /*将信息写入文件*/
void Read_from_File(st_em_sal *h); /*读出文件信息*/
int print_inf();/*显示文件信息信息*/
void InitSt_em_sal(st_em_sal **h); /*创建头结点*/
void create_list();/*创建链表函数*/
void search();/*查询记录函数*/
void search_by(st_em_sal *head); /*按条件查询记录*/
void modify(); /*修改记录函数*/
void delete(); /*删除记录函数*/
void count_sal();/*声明统计函数*/
void count_choose(st_em_sal *head,char department[]);/*声明统计中的选择函数*/
void count_min_s(st_em_sal *head,char department[]);/*声明计算最低工资函数*/
void count_max_s(st_em_sal *head,char department[]);/*声明计算最高工资函数*/
void count_avr_s(st_em_sal *head,char department[]);/*声明计算平均工资函数*/
void count_var_s(st_em_sal *head,char department[]);/*声明计算工资方差函数*/
int main()
{
char department[20];
int choice;
do{ /*菜单循环控制*/
menu_ad();
printf("输入您的选择:");
scanf("%d",&choice);
switch(choice) /*函数调用*/
{
case 1:create_list();break;
case 2:delete();break;
case 3:search();break;
case 4:modify();break;
case 5:count_sal();break;
case 0:exit(0);
default:printf("输入有误!重新输入!\n");
break;
}
}while(choice!=0);
return 0;
}
void menu_ad() /*管理员菜单*/
{
printf(" 职工工资管理系统\n");
printf("***************************菜单***************************\n");
printf("* * 1 录入工资记录 2 删除工资记录 * *\n");
printf("* * 3 查询工资记录 4 修改工资记录 * *\n");
printf("* * 5 统计工资信息 0 安全退出系统 * *\n");
printf("**********************************************************\n");
}
void Write_to_File(st_em_sal *L) /*将信息写入文件*/
{
FILE *fp;
st_em_sal *p;
fp=fopen("salary.sys","wb");
if(fp==NULL)
{
printf("打开文件失败!\n");
getchar();
getchar();
exit(0);
}
p=L->next;
while(p)
{
fprintf(fp,"%s %s %s %s %s %s %ld %ld %ld %ld %ld %ld %ld\n",p->name,p->stu_num,p->card_id,
p->department,p->position,p->bir_pla,p->bas_sal,p->fund,p->tax,p->bonus,p->pos_sal,p->der_sal,p->act_sal);
p=p->next;
}
fclose(fp);
}
void Read_from_File(st_em_sal *h) /*读出文件信息*/
{
FILE *fp;
st_em_sal *p,*q;
int i;
fp=fopen("salary.sys","rb");
if(fp==NULL)
{
printf("打开文件失败!\n");
exit(0);
}
q=h;
while(!feof(fp))
{
p=(st_em_sal *)malloc(sizeof(st_em_sal));
i=fscanf(fp,"%s %s %s %s %s %s %ld %ld %ld %ld %ld %ld %ld\n",p->name,p->stu_num,p->card_id,
p->department,p->position,p->bir_pla,&p->bas_sal,&p->fund,&p->tax,&p->bonus,&p->pos_sal,&p->der_sal,&p->act_sal);
if(i == EOF)
break;
q->next=p;
q=p;
}
q->next = NULL;
fclose(fp);
}
int print_inf() /*显示文件信息*/
{
st_em_sal *head = NULL;
st_em_sal *p;
InitSt_em_sal(&head);
Read_from_File(head);
p=head->next;
system("clear");
if(!p)
{
printf("文件中无内容!");
printf("\n按任意键键返回\n");
getchar();
getchar();
return 0;
}
printf("工号 姓名 部门 职位 籍贯 基本工资 应发工资 实发工资\n\n");
while(p)
{
printf("%-6s%-8s%-17s%-12s%-12s%-9ld%-9ld%-9ld\n",p->stu_num,p->name,p->department,
p->position,p->bir_pla,p->bas_sal,p->der_sal,p->act_sal);
p=p->next;
}
printf("\n按任意键返回\n");
getchar();
getchar();
return 1;
}
void InitSt_em_sal(st_em_sal **h) /*创建头结点*/
{
(*h)=(st_em_sal *)malloc(sizeof(st_em_sal));
if(h==NULL)
{
printf("创建文件失败!\n");
getchar();
getchar();
exit(0);
}
(*h)->next=NULL;
}
void create_list() /*创建链表函数*/
{
FILE *fp;
char ch;
st_em_sal *head;
st_em_sal *p,*p1,*q;
InitSt_em_sal(&head);
p1=head;
int size=sizeof(st_em_sal);
while(1) /*循环条件*/
{
system("clear");
printf("*录入职工工资信息*\n");
p=(st_em_sal *)malloc(size);
printf("输入职工工号:");
scanf("%s",p->stu_num);
printf("输入职工身份证号:");
scanf("%s",p->card_id);
printf("输入职工姓名:");
scanf("%s",p->name);
printf("输入职工部门:");
scanf("%s",p->department);
while(strcmp(p->department,"shebeichu")!=0&&strcmp(p->department,"renshichu")!=0&&
strcmp(p->department,"xuegongchu")!=0&&strcmp(p->department,"ruanjianxueyuan")!=0)
{ /*部门合法性校验*/
printf("无此部门!请重新输入!\n");
printf("输入职工部门:");
scanf("%s",p->department);
}
printf("输入职工职务:");
scanf("%s",p->position);
while(strcmp(p->position,"guyuan")!=0&&strcmp(p->position,"jingli")!=0&&
strcmp(p->position,"jinglizhuli")!=0) /*职务合法性校验*/
{
printf("无此职务!请重新输入!\n");
printf("输入职工职务:");
scanf("%s",p->position);
}
printf("输入职工籍贯:");
scanf("%s",p->bir_pla);
printf("输入职工基本工资:");
scanf("%ld",&(p->bas_sal));
printf("输入职工基金:");
scanf("%ld",&(p->fund));
printf("输入职工税金:");
scanf("%ld",&(p->tax));
while(p->tax>=p->bas_sal*0.05)
{
printf("输入有误!请重新输入!\n");
printf("输入职工税金:");
scanf("%ld",&(p->tax));
}
printf("输入职工奖金:");
scanf("%ld",&(p->bonus));
printf("输入职工岗位工资:");
scanf("%ld",&(p->pos_sal));
p->der_sal=p->bas_sal+p->pos_sal+p->bonus;
p->act_sal=p->der_sal-p->fund-p->tax;
p->next=p1->next;
p1->next=p;
p1=p;
printf("按任意键继续录入,按N(n)结束录入:");
getchar();
ch=getchar();
if(ch=='N'||ch=='n')
break;
}
fp=fopen("salary.sys","ab");
if(fp==NULL)
{
printf("打开文件失败!\n");
getchar();
getchar();
exit(0);
}
q=head->next;
while(q)
{
fprintf(fp,"%s %s %s %s %s %s %ld %ld %ld %ld %ld %ld %ld\n",q->name,q->stu_num,q->card_id,
q->department,q->position,q->bir_pla,q->bas_sal,q->fund,q->tax,q->bonus,q->pos_sal,q->der_sal,q->act_sal);
q=q->next;
}
fclose(fp);
}
void search_by(st_em_sal *head) /*按条件查询记录*/
{
char stu_xinxi[20];
st_em_sal *p;
char ch;
p=head->next;
do{
system("clear");
printf("\n请输入需要查询的职工工号或姓名:");
scanf("%s",stu_xinxi);
while(p!=NULL)
{
if(strcmp(p->stu_num,stu_xinxi)==0||strcmp(p->name,stu_xinxi)==0)
{
printf("工号:%s\n",p->stu_num);
printf("姓名:%s\n",p->name);
printf("身份证号:%s\n",p->card_id);
printf("部门:%s\n",p->department);
printf
展开阅读全文