0%

C语言|最简管理系统

C语言结课作业:编写一个小型工资管理系统,用来管理职工的个人基本信息及工资薪酬等数据。在技术要求方面仅仅是要求了使用结构体数据类型,但基于我们的学习进度,考察的应该是用数组来储存。

作业要求

  1. 每个职工的数据应包括:工号、姓名、性别、部门、基本工资、绩效工资、奖金、应发工资(应发工资=基本工资+绩效工资+奖金)。职工数据要求采用结构体数据类型。

  2. 菜单显示:显示系统的一级功能菜单(数据输入、数据修改、数据处理、数据输出、退出)。

  3. 数据输入:至少输入10个职工的各项数据(应发工资由系统自动计算,不需要输入)。录入的第一条记录用自已的真实姓名,部门为自己的真实班级。并将有自己真实姓名、班级的输出结果截屏保存到大作业总结报告中。

  4. 数据修改:输入工号,修改指定工号的各项数据。输出修改完成后的全部职工数据。

  5. 数据处理:处理方式包括:排序、查询。可提供子菜单让用户选择。其中:

    1)排序:按工号排序,显示所有职工的全部数据。

    2)查询:按工号查询,显示指定工号的全部数据。

  6. 数据输出:输出全部职工的各项数据。

  7. 退出:退出整个工资管理系统。

整体框架

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 },

};

另外还需要定义一个全局的数据库长度

1
int lenth = 3;

之所以直接定义为一个常量,而不是用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(){}

函数结构如下

image-20200615101249209

这些函数都会对全局中的数据库进行操作。

菜单系统

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数据库实现同样增删改查的操作。

所以呀,流水的编程语言,铁打的管理系统,入门从管理系统开始!