- 添加职工信息:包括工号、姓名、性别、年龄、工资等。
- 显示所有职工信息:以表格形式展示所有已存储的职工。
- 查找职工信息:可以通过工号或姓名进行查找。
- 修改职工信息:根据工号找到职工并修改其信息。
- 删除职工信息:根据工号删除职工记录。
- 数据排序:可以按工资或年龄进行排序。
- 数据保存与加载:将数据从文件读取到内存,并将内存中的数据保存到文件,实现数据持久化。
设计思路
-
数据结构:
(图片来源网络,侵删)- 使用
struct来定义职工的数据结构,包含所需的各种信息。 - 使用一个结构体数组
struct Employee emp[MAX]来在内存中存储所有职工信息。MAX是一个宏,定义最大职工数量。 - 使用一个全局变量
int count来记录当前系统中职工的实际数量。
- 使用
-
模块化设计:
- 将每个功能(如添加、显示、查找等)都封装成一个独立的函数。
- 编写一个主菜单函数
menu()来显示操作选项,并根据用户的选择调用相应的功能函数,这使main函数非常简洁,易于维护。
-
文件操作:
- 使用
fopen,fread,fwrite,fclose等标准C库函数进行文件读写。 - 在程序启动时,尝试从一个文件(如
employees.dat)中加载数据。 - 在每次对数据进行修改(添加、删除、修改)后,将整个数据数组重新写回文件,确保数据不丢失。
- 使用
完整代码实现
下面是完整的C语言代码,你可以直接复制到一个 .c 文件中(employee_management.c)进行编译和运行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),在Windows下按任意键继续
#include <ctype.h> // 用于 toupper()
// 定义最大职工数量
#define MAX 1000
// 职工结构体
struct Employee {
int id; // 工号
char name[50]; // 姓名
char gender[10];// 性别
int age; // 年龄
float salary; // 工资
};
// 全局变量
struct Employee emp[MAX]; // 职工数组
int count = 0; // 当前职工数量
// 函数声明
void menu();
void addEmployee();
void displayEmployees();
void searchEmployee();
void modifyEmployee();
void deleteEmployee();
void sortEmployees();
void saveToFile();
void loadFromFile();
void clearInputBuffer();
int main() {
loadFromFile(); // 程序启动时加载数据
menu();
return 0;
}
// 显示主菜单
void menu() {
int choice;
while (1) {
system("cls"); // Windows下清屏,Linux/macOS用 system("clear");
printf("\n\n");
printf("========================================\n");
printf("= 职工信息管理系统 v1.0 =\n");
printf("========================================\n");
printf("= 1. 添加职工信息 =\n");
printf("= 2. 显示所有职工信息 =\n");
printf("= 3. 查找职工信息 =\n");
printf("= 4. 修改职工信息 =\n");
printf("= 5. 删除职工信息 =\n");
printf("= 6. 职工信息排序 =\n");
printf("= 0. 退出系统 =\n");
printf("========================================\n");
printf("请输入您的选择 (0-6): ");
if (scanf("%d", &choice) != 1) {
printf("输入无效,请输入数字!\n");
clearInputBuffer();
getch();
continue;
}
clearInputBuffer(); // 清除输入缓冲区中的换行符等
switch (choice) {
case 1:
addEmployee();
break;
case 2:
displayEmployees();
break;
case 3:
searchEmployee();
break;
case 4:
modifyEmployee();
break;
case 5:
deleteEmployee();
break;
case 6:
sortEmployees();
break;
case 0:
saveToFile(); // 退出前保存数据
printf("\n感谢使用,系统已退出!\n");
exit(0);
default:
printf("\n无效的选择,请重新输入!\n");
}
printf("\n按任意键返回主菜单...");
getch();
}
}
// 添加职工信息
void addEmployee() {
if (count >= MAX) {
printf("\n职工数量已达上限,无法添加!\n");
return;
}
system("cls");
printf("\n--- 添加职工信息 ---\n");
struct Employee e;
printf("请输入工号: ");
scanf("%d", &e.id);
clearInputBuffer();
// 检查工号是否已存在
for (int i = 0; i < count; i++) {
if (emp[i].id == e.id) {
printf("\n错误:该工号已存在!\n");
return;
}
}
printf("请输入姓名: ");
fgets(e.name, sizeof(e.name), stdin);
e.name[strcspn(e.name, "\n")] = 0; // 去掉fgets读取的换行符
printf("请输入性别: ");
fgets(e.gender, sizeof(e.gender), stdin);
e.gender[strcspn(e.gender, "\n")] = 0;
printf("请输入年龄: ");
scanf("%d", &e.age);
clearInputBuffer();
printf("请输入工资: ");
scanf("%f", &e.salary);
clearInputBuffer();
emp[count++] = e; // 将新职工加入数组,并增加计数
printf("\n职工信息添加成功!\n");
}
// 显示所有职工信息
void displayEmployees() {
if (count == 0) {
printf("\n系统中没有职工信息!\n");
return;
}
system("cls");
printf("\n--- 所有职工信息 ---\n");
printf("-----------------------------------------------------------------\n");
printf("| %-10s | %-15s | %-8s | %-6s | %-10s |\n", "工号", "姓名", "性别", "年龄", "工资");
printf("-----------------------------------------------------------------\n");
for (int i = 0; i < count; i++) {
printf("| %-10d | %-15s | %-8s | %-6d | %-10.2f |\n",
emp[i].id, emp[i].name, emp[i].gender, emp[i].age, emp[i].salary);
}
printf("-----------------------------------------------------------------\n");
}
// 查找职工信息
void searchEmployee() {
if (count == 0) {
printf("\n系统中没有职工信息!\n");
return;
}
system("cls");
printf("\n--- 查找职工信息 ---\n");
int option;
printf("1. 按工号查找\n");
printf("2. 按姓名查找\n");
printf("请选择查找方式 (1-2): ");
scanf("%d", &option);
clearInputBuffer();
if (option == 1) {
int id;
printf("请输入要查找的工号: ");
scanf("%d", &id);
clearInputBuffer();
int found = 0;
for (int i = 0; i < count; i++) {
if (emp[i].id == id) {
found = 1;
printf("\n找到职工信息:\n");
printf("-----------------------------------------------------------------\n");
printf("| %-10s | %-15s | %-8s | %-6s | %-10s |\n", "工号", "姓名", "性别", "年龄", "工资");
printf("-----------------------------------------------------------------\n");
printf("| %-10d | %-15s | %-8s | %-6d | %-10.2f |\n",
emp[i].id, emp[i].name, emp[i].gender, emp[i].age, emp[i].salary);
printf("-----------------------------------------------------------------\n");
break;
}
}
if (!found) {
printf("\n未找到工号为 %d 的职工!\n", id);
}
} else if (option == 2) {
char name[50];
printf("请输入要查找的姓名: ");
fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = 0;
int found = 0;
printf("\n查找结果:\n");
printf("-----------------------------------------------------------------\n");
printf("| %-10s | %-15s | %-8s | %-6s | %-10s |\n", "工号", "姓名", "性别", "年龄", "工资");
printf("-----------------------------------------------------------------\n");
for (int i = 0; i < count; i++) {
if (strstr(emp[i].name, name) != NULL) { // 使用strstr进行模糊查找
found = 1;
printf("| %-10d | %-15s | %-8s | %-6d | %-10.2f |\n",
emp[i].id, emp[i].name, emp[i].gender, emp[i].age, emp[i].salary);
}
}
if (!found) {
printf("\n未找到姓名包含 \"%s\" 的职工!\n", name);
}
printf("-----------------------------------------------------------------\n");
} else {
printf("\n无效的选择!\n");
}
}
// 修改职工信息
void modifyEmployee() {
if (count == 0) {
printf("\n系统中没有职工信息!\n");
return;
}
system("cls");
printf("\n--- 修改职工信息 ---\n");
int id;
printf("请输入要修改的职工工号: ");
scanf("%d", &id);
clearInputBuffer();
for (int i = 0; i < count; i++) {
if (emp[i].id == id) {
printf("\n已找到该职工,请输入新的信息(不修改则直接回车):\n");
char input[100];
printf("姓名 [%s]: ", emp[i].name);
fgets(input, sizeof(input), stdin);
if (strlen(input) > 1) { // 如果输入了内容
input[strcspn(input, "\n")] = 0;
strcpy(emp[i].name, input);
}
printf("性别 [%s]: ", emp[i].gender);
fgets(input, sizeof(input), stdin);
if (strlen(input) > 1) {
input[strcspn(input, "\n")] = 0;
strcpy(emp[i].gender, input);
}
printf("年龄 [%d]: ", emp[i].age);
fgets(input, sizeof(input), stdin);
if (strlen(input) > 1) {
emp[i].age = atoi(input);
}
printf("工资 [%.2f]: ", emp[i].salary);
fgets(input, sizeof(input), stdin);
if (strlen(input) > 1) {
emp[i].salary = atof(input);
}
printf("\n职工信息修改成功!\n");
return;
}
}
printf("\n未找到工号为 %d 的职工!\n", id);
}
// 删除职工信息
void deleteEmployee() {
if (count == 0) {
printf("\n系统中没有职工信息!\n");
return;
}
system("cls");
printf("\n--- 删除职工信息 ---\n");
int id;
printf("请输入要删除的职工工号: ");
scanf("%d", &id);
clearInputBuffer();
for (int i = 0; i < count; i++) {
if (emp[i].id == id) {
// 将后面的所有元素前移一位
for (int j = i; j < count - 1; j++) {
emp[j] = emp[j + 1];
}
count--; // 职工总数减一
printf("\n工号为 %d 的职工信息已删除!\n", id);
return;
}
}
printf("\n未找到工号为 %d 的职工!\n", id);
}
// 职工信息排序
void sortEmployees() {
if (count == 0) {
printf("\n系统中没有职工信息!\n");
return;
}
system("cls");
printf("\n--- 职工信息排序 ---\n");
int option;
printf("1. 按工资升序排序\n");
printf("2. 按工资降序排序\n");
printf("3. 按年龄升序排序\n");
printf("4. 按年龄降序排序\n");
printf("请选择排序方式 (1-4): ");
scanf("%d", &option);
clearInputBuffer();
// 使用简单的冒泡排序
for (int i = 0; i < count - 1; i++) {
for (int j = 0; j < count - i - 1; j++) {
int should_swap = 0;
if (option == 1 && emp[j].salary > emp[j + 1].salary) should_swap = 1;
if (option == 2 && emp[j].salary < emp[j + 1].salary) should_swap = 1;
if (option == 3 && emp[j].age > emp[j + 1].age) should_swap = 1;
if (option == 4 && emp[j].age < emp[j + 1].age) should_swap = 1;
if (should_swap) {
struct Employee temp = emp[j];
emp[j] = emp[j + 1];
emp[j + 1] = temp;
}
}
}
printf("\n排序完成!\n");
displayEmployees(); // 排序后显示结果
}
// 将数据保存到文件
void saveToFile() {
FILE *fp = fopen("employees.dat", "wb");
if (fp == NULL) {
printf("\n无法打开文件进行保存!\n");
return;
}
// 一次写入整个结构体数组
fwrite(emp, sizeof(struct Employee), count, fp);
fclose(fp);
printf("\n数据已成功保存到 employees.dat 文件!\n");
}
// 从文件加载数据
void loadFromFile() {
FILE *fp = fopen("employees.dat", "rb");
if (fp == NULL) {
// 文件不存在是正常情况(首次运行)
return;
}
// 一次读取整个结构体数组
count = fread(emp, sizeof(struct Employee), MAX, fp);
fclose(fp);
printf("\n数据已成功从 employees.dat 文件加载!\n");
}
// 清除输入缓冲区
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
如何编译和运行
- 保存代码:将上面的代码保存为
employee_management.c。 - 编译:打开终端或命令提示符,使用GCC进行编译。
gcc employee_management.c -o employee_management
- 运行:
- 在 Windows 上:直接运行生成的
employee_management.exe文件。 - 在 Linux/macOS 上:在终端中运行
./employee_management。
- 在 Windows 上:直接运行生成的
注意:
- 代码中使用了
system("cls")来清屏,这是Windows特有的,如果你在Linux或macOS上运行,需要将其改为system("clear")。 getch()函数用于实现“按任意键继续”的功能,它包含在<conio.h>头文件中,这个头文件在标准C中不存在,但在Windows的编译器(如Visual Studio, MinGW)中可用,如果你在Linux/macOS上编译,需要用其他方法替代,printf("Press Enter to continue..."); getchar();。fgets()用于安全地读取字符串,可以防止缓冲区溢出,读取后需要手动移除末尾的换行符\n。
功能演示简述
- 启动:程序会自动尝试从
employees.dat加载数据。 - 添加:选择
1,按照提示输入职工信息,系统会检查工号是否重复。 - 显示:选择
2,以清晰的表格形式列出所有职工。 - 查找:选择
3,可以选择按工号精确查找或按姓名模糊查找。 - 修改:选择
4,输入工号后,可以逐项修改职工信息,不修改的项直接按回车即可。 - 删除:选择
5,输入工号,系统会找到并删除该职工,后面的职工信息会自动前移填补空缺。 - 排序:选择
6,可以按工资或年龄进行升序或降序排列。 - 退出:选择
0,系统会先将所有数据保存到employees.dat文件,然后退出,下次启动时,数据会自动恢复。
这个系统设计虽然使用了数组,对于超大规模数据(超过MAX)会不够用,但对于学习C语言和掌握基本的数据结构、文件操作、模块化编程思想来说,是一个非常经典和完整的示例。
