C语言结课作业:编写一个小型工资管理系统,用来管理职工的个人基本信息及工资薪酬等数据。在技术要求方面仅仅是要求了使用结构体数据类型,但基于我们的学习进度,考察的应该是用数组来储存。
作业要求
每个职工的数据应包括:工号、姓名、性别、部门、基本工资、绩效工资、奖金、应发工资(应发工资=基本工资+绩效工资+奖金)。职工数据要求采用结构体数据类型。
菜单显示:显示系统的一级功能菜单(数据输入、数据修改、数据处理、数据输出、退出)。
数据输入:至少输入10个职工的各项数据(应发工资由系统自动计算,不需要输入)。录入的第一条记录用自已的真实姓名,部门为自己的真实班级。并将有自己真实姓名、班级的输出结果截屏保存到大作业总结报告中。
数据修改:输入工号,修改指定工号的各项数据。输出修改完成后的全部职工数据。
数据处理:处理方式包括:排序、查询。可提供子菜单让用户选择。其中:
1)排序:按工号排序,显示所有职工的全部数据。
2)查询:按工号查询,显示指定工号的全部数据。
数据输出:输出全部职工的各项数据。
退出:退出整个工资管理系统。
整体框架
1.数据存储
我使用的是结构体数组来自建一个数据库,放在全局环境下,将数据库设为一个全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| struct staff { int id; char name[20]; char sex[20]; char belong[20]; int basic_pay; int add_pay; int reward_pay; int all_pay;
}data[999] = { {44, "张三", "男", "技术部", 5000, 1000, 200, 6200 }, {14, "李四", "男", "运维部", 4000, 1000, 200, 5200 }, {56, "小红", "女", "网安部", 3000, 1000, 200, 4200 }, };
|
另外还需要定义一个全局的数据库长度
之所以直接定义为一个常量,而不是用sizeof这种方式来计算数组长度,因为我发现结构体数组用这种方式来计算数组长度会是一个大坑!所以还不如手动添加常量
2.函数功能结构
(1)函数声明
1 2 3 4 5 6 7 8 9 10
| //函数声明 int create(); //增 int del(); //删 int edit(); //改
int process(); //处理 int req(); //查 int line(); //排
int showall(); //查询全部
|
(2)函数定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| int main(void){
int order;
while(1){ printf("****************************\n"); printf("主菜单:\n"); printf("1.输入员工信息\n"); printf("2.删除员工信息\n"); printf("3.修改员工信息\n"); printf("4.处理员工信息\n"); printf("5.显示所有员工信息\n"); printf("6.退出\n"); printf("****************************\n"); printf("---请输入菜单项:---\n");
scanf("%d",&order); if(order==6){ system("cls"); return 0; } switch(order){ case 1: create();break; case 2: del();break; case 3: edit();break; case 4: process();break; case 5: showall(); break; default: printf("\n404 NOT FOUND!"); getchar(); getchar(); system("cls"); } }
}
int create() {}
int del(){}
int edit(){}
int process(){}
int line(){}
int req(){}
int showall(){}
|
函数结构如下
这些函数都会对全局中的数据库进行操作。
菜单系统
main函数这里,就构建整体的函数调用框架,即本管理系统的菜单系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| int main(void){ int order;
while(1){
printf("****************************\n"); printf("主菜单:\n"); printf("1.输入员工信息\n"); printf("2.删除员工信息\n"); printf("3.修改员工信息\n"); printf("4.处理员工信息\n"); printf("5.显示所有员工信息\n"); printf("6.退出\n"); printf("****************************\n"); printf("---请输入菜单项:---\n");
scanf("%d",&order); if(order==6){ system("cls"); return 0; } switch(order){ case 1: create();break; case 2: del();break; case 3: edit();break; case 4: process();break; case 5: showall(); break; default: printf("\n404 NOT FOUND!"); getchar(); getchar(); system("cls"); } }
}
|
菜单系统常用switch语句来调用各个函数,另外为了整个管理系统的输出整洁一点,我还用了
“stdlib.h”库中的清屏函数system(“cls”)
增添员工信息
增添员工信息的基本设计思路:将新的信息填入到下一个数组空的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| int create() { int i; i = lenth; printf("\n"); printf("新增员工工号:"); scanf("%d", &data[i].id); printf("\n"); printf("新增员工姓名:"); scanf("%s", &data[i].name); printf("\n");
printf("新增员工性别:"); scanf("%s", &data[i].sex); printf("\n"); printf("新增员工所属部门:"); scanf("%s", &data[i].belong); printf("\n"); printf("新增员工基本工资:"); scanf("%d", &data[i].basic_pay); printf("\n"); printf("新增员工绩效工资:"); scanf("%d", &data[i].add_pay); printf("\n"); printf("新增员工奖金:"); scanf("%d", &data[i].reward_pay); printf("\n"); data[i].all_pay = data[i].basic_pay + data[i].add_pay + data[i].reward_pay; printf("创建成功!\n"); lenth++; getchar(); getchar(); system("cls"); }
|
用在全局定义的lenth(突然发现自己记错了长度的英语单词2333)来确定新数据的填写地址,创建成功后要注意用lenth++
,拓展数据的长度。
删除员工信息
删除员工信息的基本设计思路是:通过遍历所有的数据查询到指定的员工工号,然后将后面的数据依次向上填补被“删除”的空白
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| int del(){ int i = lenth; int num; printf("\n请输入删除员工工号:"); scanf("%d", &num); for(int j=0; j<=i+1; j++){ if(num==data[j].id){ for( ;j<=i-j; j++){ data[j] = data[j+1]; } lenth--; printf("\n删除成功!\n"); break; } if(j==i+1){ printf("\n查无此人!\n"); break; } } getchar(); getchar(); system("cls"); }
|
在遍历中用到了两个if语句,if(num==data[j].id)来寻找符合条件的员工号,而if(j==i+1)
则是遍历所有的数据后未找到匹配条件。
说是删除实践上只是删除的数组元素的地位(下标)和财产(数据)被下一个数组元素给继承了,而下一个的数据元素的下标和数据又被下下个数据元素继承,以此类推。这里同样要注意用lenth--
缩短数据长度。
修改员工信息
修改员工信息的思路和删除员工信息的思路相差无几:都需要查询定位对应的员工信息,不同的是定位后,这个还要修改员工的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| int edit(){ int i = lenth; int num; printf("\n请输入需要修改的员工工号:"); scanf("%d", &num); printf("\n"); for(int j=0; j<=i+1; j++){ if(num==data[j].id){ printf("修改姓名:"); scanf("%s", &data[j].name); printf("\n"); printf("修改性别:"); scanf("%s", &data[j].sex); printf("\n"); printf("修改所属部门:"); scanf("%s", &data[j].belong); printf("\n"); printf("修改基本工资:"); scanf("%d", &data[j].basic_pay); printf("\n"); printf("修改绩效工资:"); scanf("%d", &data[j].add_pay); printf("\n"); printf("修改奖金:"); scanf("%d", &data[j].reward_pay); printf("\n"); data[j].all_pay = data[j].basic_pay + data[j].add_pay + data[j].reward_pay; printf("修改成功!\n"); showall(); break;
} if(j==i+1){ printf("\n查无此人!\n"); break; } } getchar(); getchar(); system("cls"); }
|
所谓修改,无非是重新赋值罢了。
处理信息
处理信息分成了排序信息和查询信息两部分,所有采用菜单系统同样的方式来设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| int process(){ int order; printf("---------------------------------------------\n"); printf("1.员工信息排序 2.员工信息查询\n"); printf("---------------------------------------------\n"); printf("请选择处理方式:"); scanf("%d",&order); printf("\n"); switch(order){ case 1: line(); break; case 2: req(); break; } }
|
1.信息排序
说实话这个函数的设计是该项目唯一卡到我的地方,因为我一直把它理解成了“排序处理”,但我了解实际上的需求应该是“排序输出”,那问题就简单很多了,我的设计思路如下
将每个数组元素的地址看作是它们的住址,而员工工号信息就是它们的门牌号,把它们的门牌号记录下来,然后排列大小顺序,按顺序去拜访它们,期间它们的住处时是没有发生改变的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| int line(){ int i; int id_data[100]; i = lenth; char* str[8] = {"工号", "姓名", "性别", "部门", "基本工资", "绩效工资", "奖金", "应发工资"}; for(int j = 0; j<i; j++){ id_data[j] = data[j].id; } qsort(id_data, i, sizeof(id_data[0]) , cmp);
printf("\n排序成功!\n\n") ;
for(int n=0; n<8; n++){ printf("%-12s" , str[n]); } printf("\n\n");
for(int n1 = 0; n1<i; n1++){ for(int n2 = 0; n2<i; n2++ ){ if(id_data[n1] == data[n2].id){ printf(" %-10d", data[n2].id); printf(" %-10s", data[n2].name); printf(" %-10s", data[n2].sex); printf("%-10s", data[n2].belong); printf(" %-10d", data[n2].basic_pay); printf(" %-10d", data[n2].add_pay); printf(" %-10d", data[n2].reward_pay); printf(" %-10d", data[n2].all_pay ); printf("\n\n"); } } } getchar(); getchar(); system("cls"); }
|
依据代码,我的思路对应关系如下
- 住址 ==> 数组元素下标,即
data
数组的下标
- 门牌号 ==>
data[j].id
- 记录门牌号 ==> 用了另一个数组:
id_data[j]
来储存
- 排列门牌号大小 ==> 将
id_data[j]
存储的门牌号排序,这里使用了C语言内置的排序函数:qsort()
- 依次拜访 ==> 两层循环,外层循环:
for(int n1 = 0; n1<i; n1++)
循环名单上排列好的门牌号,内层循环:for(int n2 = 0; n2<i; n2++ )
,一个个去找符合名单上第一位的门牌号,然后输出
另外注意,作为一个大学生的作业,使用内置的qsort()排序函数应该是非法的(狗头),应该使用冒泡排序或选择排序!
好,我摊牌啦,我就是想偷一下懒……
2.查询员工信息
查询的思路和删除信息,修改信息相似,没什么特别的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| int req(){ int i = lenth; int num; char* str[8] = {"工号", "姓名", "性别", "部门", "基本工资", "绩效工资", "奖金", "应发工资"}; printf("\n请输入需要查询员工工号:"); scanf("%d", &num); printf("\n\n"); for(int n=0; n<8; n++){ printf("%-12s" , str[n]); } printf("\n\n"); for(int j=0; j<=i+1; j++){ if(num==data[j].id){ printf(" %-10d", data[j].id); printf(" %-10s", data[j].name); printf(" %-10s", data[j].sex); printf("%-10s", data[j].belong); printf(" %-10d", data[j].basic_pay); printf(" %-10d", data[j].add_pay); printf(" %-10d", data[j].reward_pay); printf(" %-10d", data[j].all_pay ); printf("\n\n"); printf("\n查询成功!\n\n"); break;
} if(j==i+1){ printf(" 无\n"); printf("\n查无此人!\n"); break; } }
getchar(); getchar(); system("cls");
}
|
这里输出数据表的表头,用了数组来存储字符串,要注意加号: `char str[8]`
查询全部数据
无脑遍历输出即可,就是输出格式上要有调整,一般可以用printf("%-9d")
占9个空格,左对齐的方式来调整输出格式,输出那里我也是为了美观才一个个去加空格调整格式,就不要吐槽我代码格式不整洁了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| int showall(){ int i; char* str[8] = {"工号", "姓名", "性别", "部门", "基本工资", "绩效工资", "奖金", "应发工资"}; i = lenth - 1; data[i].all_pay = data[i].basic_pay + data[i].add_pay + data[i].reward_pay; printf("\n"); printf("查询成功!\n\n");
for(int n=0; n<8; n++){ printf("%-12s" , str[n]); } printf("\n\n"); for(int j=0; j<=i; j++){ printf(" %-10d", data[j].id); printf(" %-10s", data[j].name); printf(" %-10s", data[j].sex); printf("%-10s", data[j].belong); printf(" %-10d", data[j].basic_pay); printf(" %-10d", data[j].add_pay); printf(" %-10d", data[j].reward_pay); printf(" %-10d", data[j].all_pay ); printf("\n\n"); }
getchar(); getchar(); system("cls"); }
|
总结
整体来说,这个结课作业并不难,只用用课堂上的知识完全是可以完成了(我一个下午不到就写好)。
但事实上无论用哪门语言,增删改查的实现永远是入门重要的第一课,本项目和之前的python学生管理系统,都仅仅是在内部实现的数据增删改查,一旦退出程序,缓存就被清除了,无法保留。所以我们还应考虑——如何把这样的操作在文本中实现,如何连接mysql数据库实现同样增删改查的操作。
所以呀,流水的编程语言,铁打的管理系统,入门从管理系统开始!