C语言课程设计:职工信息管理系统
项目概述
本项目旨在使用C语言开发一个基于控制台的职工信息管理系统,该系统将实现对职工信息的增加、删除、修改、查询、显示以及数据保存到文件和从文件加载等基本功能,通过本项目,可以综合运用C语言的结构体、指针、文件操作、排序算法等核心知识点,锻炼编程和解决问题的能力。
需求分析
系统需要具备以下核心功能:
- 数据录入:能够从键盘输入新职工的信息,并将其添加到系统中。
- 数据删除:能够根据职工编号或姓名删除指定职工的信息。
- 数据修改:能够根据职工编号或姓名找到职工,并修改其部分或全部信息。
- 数据查询:能够根据职工编号或姓名查询职工信息,并显示结果。
- 数据浏览:能够以列表形式显示所有职工的信息。
- 数据排序:能够按照职工编号或工资进行升序/降序排序。
- 数据持久化:系统能够将所有职工信息保存到磁盘文件中,并在程序启动时自动加载,实现数据不丢失。
功能设计
为了满足上述需求,设计如下菜单驱动界面:
+-------------------------------------+
| 职工信息管理系统 v1.0 |
+-------------------------------------+
| 1. 添加职工信息 |
| 2. 删除职工信息 |
| 3. 修改职工信息 |
| 4. 查询职工信息 |
| 5. 显示所有职工 |
| 6. 按工资排序 |
| 0. 退出系统 |
+-------------------------------------+
用户通过输入数字选择对应功能,系统执行相应操作后返回主菜单。
数据结构设计
为了存储职工信息,定义一个结构体 Employee:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),实现不回显的输入
// 定义职工结构体
typedef struct {
int id; // 职工编号
char name[50]; // 职工姓名
char gender[10];// 性别
int age; // 年龄
float salary; // 工资
} Employee;
// 定义一个动态数组来存储所有职工
Employee *employees = NULL;
int employee_count = 0; // 当前职工数量
int capacity = 0; // 数组容量
使用动态数组 (malloc, realloc) 可以灵活地管理职工数量,避免静态数组大小固定的限制。
核心功能模块实现
以下是各个功能模块的C语言实现代码。
1 主菜单与主函数
// 函数声明
void add_employee();
void delete_employee();
void modify_employee();
void search_employee();
void display_all_employees();
void sort_by_salary();
void save_to_file();
void load_from_file();
void free_memory();
int main() {
// 程序启动时,尝试从文件加载数据
load_from_file();
int choice;
while (1) {
system("cls"); // 清屏 (Windows系统)
// system("clear"); // 清屏 (Linux/macOS系统)
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("请输入您的选择: ");
scanf("%d", &choice);
getchar(); // 消耗掉scanf留下的换行符
switch (choice) {
case 1: add_employee(); break;
case 2: delete_employee(); break;
case 3: modify_employee(); break;
case 4: search_employee(); break;
case 5: display_all_employees(); break;
case 6: sort_by_salary(); break;
case 0:
save_to_file(); // 退出前保存数据
free_memory(); // 释放内存
printf("感谢使用,再见!\n");
system("pause");
exit(0);
default:
printf("无效的输入,请重新选择!\n");
system("pause");
}
}
return 0;
}
2 添加职工信息
void add_employee() {
system("cls");
printf("--- 添加职工信息 ---\n");
// 检查是否需要扩容
if (employee_count >= capacity) {
capacity = (capacity == 0) ? 2 : capacity * 2;
employees = (Employee *)realloc(employees, capacity * sizeof(Employee));
if (employees == NULL) {
printf("内存分配失败!\n");
system("pause");
return;
}
}
Employee e;
printf("请输入职工编号: ");
scanf("%d", &e.id);
getchar(); // 消耗换行符
// 检查编号是否已存在
for (int i = 0; i < employee_count; i++) {
if (employees[i].id == e.id) {
printf("错误:该职工编号已存在!\n");
system("pause");
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);
getchar();
printf("请输入工资: ");
scanf("%f", &e.salary);
getchar();
employees[employee_count++] = e;
printf("职工信息添加成功!\n");
system("pause");
}
3 删除职工信息
void delete_employee() {
system("cls");
printf("--- 删除职工信息 ---\n");
if (employee_count == 0) {
printf("系统中没有职工信息!\n");
system("pause");
return;
}
int id;
printf("请输入要删除的职工编号: ");
scanf("%d", &id);
getchar();
int found = 0;
for (int i = 0; i < employee_count; i++) {
if (employees[i].id == id) {
found = 1;
// 将后面的元素前移
for (int j = i; j < employee_count - 1; j++) {
employees[j] = employees[j + 1];
}
employee_count--;
printf("职工编号为 %d 的信息已删除!\n", id);
break;
}
}
if (!found) {
printf("未找到职工编号为 %d 的职工!\n", id);
}
system("pause");
}
4 修改职工信息
void modify_employee() {
system("cls");
printf("--- 修改职工信息 ---\n");
if (employee_count == 0) {
printf("系统中没有职工信息!\n");
system("pause");
return;
}
int id;
printf("请输入要修改的职工编号: ");
scanf("%d", &id);
getchar();
int found = 0;
for (int i = 0; i < employee_count; i++) {
if (employees[i].id == id) {
found = 1;
printf("找到职工: %s\n", employees[i].name);
printf("请输入新的姓名 (直接回车保持原值): ");
char new_name[50];
fgets(new_name, sizeof(new_name), stdin);
if (strlen(new_name) > 1) { // 如果用户输入了内容
new_name[strcspn(new_name, "\n")] = 0;
strcpy(employees[i].name, new_name);
}
printf("请输入新的性别 (直接回车保持原值): ");
char new_gender[10];
fgets(new_gender, sizeof(new_gender), stdin);
if (strlen(new_gender) > 1) {
new_gender[strcspn(new_gender, "\n")] = 0;
strcpy(employees[i].gender, new_gender);
}
printf("请输入新的年龄 (输入0保持原值): ");
int new_age;
scanf("%d", &new_age);
getchar();
if (new_age != 0) {
employees[i].age = new_age;
}
printf("请输入新的工资 (输入-1保持原值): ");
float new_salary;
scanf("%f", &new_salary);
getchar();
if (new_salary != -1) {
employees[i].salary = new_salary;
}
printf("职工信息修改成功!\n");
break;
}
}
if (!found) {
printf("未找到职工编号为 %d 的职工!\n", id);
}
system("pause");
}
5 查询职工信息
void search_employee() {
system("cls");
printf("--- 查询职工信息 ---\n");
if (employee_count == 0) {
printf("系统中没有职工信息!\n");
system("pause");
return;
}
int id;
printf("请输入要查询的职工编号: ");
scanf("%d", &id);
getchar();
int found = 0;
for (int i = 0; i < employee_count; i++) {
if (employees[i].id == id) {
found = 1;
printf("\n--- 查询结果 ---\n");
printf("职工编号: %d\n", employees[i].id);
printf("职工姓名: %s\n", employees[i].name);
printf("性别: %s\n", employees[i].gender);
printf("年龄: %d\n", employees[i].age);
printf("工资: %.2f\n", employees[i].salary);
printf("----------------\n");
break;
}
}
if (!found) {
printf("未找到职工编号为 %d 的职工!\n", id);
}
system("pause");
}
6 显示所有职工信息
void display_all_employees() {
system("cls");
printf("--- 所有职工信息 ---\n");
if (employee_count == 0) {
printf("系统中没有职工信息!\n");
system("pause");
return;
}
printf("%-10s %-20s %-10s %-10s %-10s\n", "编号", "姓名", "性别", "年龄", "工资");
printf("------------------------------------------------\n");
for (int i = 0; i < employee_count; i++) {
printf("%-10d %-20s %-10s %-10d %-10.2f\n",
employees[i].id,
employees[i].name,
employees[i].gender,
employees[i].age,
employees[i].salary);
}
system("pause");
}
7 按工资排序
这里使用简单的冒泡排序算法,可以根据需要替换为更高效的排序算法(如快速排序)。
// 比较函数,用于qsort
int compare_salary_asc(const void *a, const void *b) {
Employee *empA = (Employee *)a;
Employee *empB = (Employee *)b;
if (empA->salary > empB->salary) return 1;
if (empA->salary < empB->salary) return -1;
return 0;
}
int compare_salary_desc(const void *a, const void *b) {
return -compare_salary_asc(a, b);
}
void sort_by_salary() {
system("cls");
printf("--- 按工资排序 ---\n");
if (employee_count == 0) {
printf("系统中没有职工信息!\n");
system("pause");
return;
}
int order;
printf("请选择排序方式:\n");
printf("1. 升序\n");
printf("2. 降序\n");
printf("请输入选择: ");
scanf("%d", &order);
getchar();
if (order == 1) {
qsort(employees, employee_count, sizeof(Employee), compare_salary_asc);
printf("已按工资升序排序!\n");
} else if (order == 2) {
qsort(employees, employee_count, sizeof(Employee), compare_salary_desc);
printf("已按工资降序排序!\n");
} else {
printf("无效的选择!\n");
system("pause");
return;
}
display_all_employees(); // 排序后直接显示
}
8 文件操作
void save_to_file() {
FILE *fp = fopen("employees.dat", "wb"); // "wb" 表示二进制写入
if (fp == NULL) {
printf("无法打开文件进行保存!\n");
return;
}
// 先写入职工数量
fwrite(&employee_count, sizeof(int), 1, fp);
// 再写入所有职工数据
fwrite(employees, sizeof(Employee), employee_count, fp);
fclose(fp);
printf("数据已成功保存到文件 employees.dat\n");
}
void load_from_file() {
FILE *fp = fopen("employees.dat", "rb"); // "rb" 表示二进制读取
if (fp == NULL) {
// 文件不存在是正常情况,说明是第一次运行
return;
}
// 读取职工数量
fread(&employee_count, sizeof(int), 1, fp);
// 根据数量分配内存
if (employee_count > 0) {
employees = (Employee *)malloc(employee_count * sizeof(Employee));
if (employees == NULL) {
printf("内存分配失败!\n");
fclose(fp);
exit(1);
}
capacity = employee_count;
// 读取所有职工数据
fread(employees, sizeof(Employee), employee_count, fp);
}
fclose(fp);
printf("数据已成功从文件加载,\n");
}
9 内存释放
void free_memory() {
if (employees != NULL) {
free(employees);
employees = NULL;
}
employee_count = 0;
capacity = 0;
}
如何编译和运行
- 保存代码:将以上所有代码块合并到一个文件中,
employee_management.c。 - 编译:打开命令行(如Windows的CMD或PowerShell,Linux的Terminal),使用GCC进行编译。
gcc employee_management.c -o employee_management.exe
- 在Linux/macOS上,编译命令为
gcc employee_management.c -o employee_management。
- 在Linux/macOS上,编译命令为
- 运行:
- 在Windows上:
employee_management.exe - 在Linux/macOS上:
./employee_management
- 在Windows上:
项目扩展与优化建议
如果这是一个课程设计,并且希望获得更高的评价,可以考虑以下扩展:
- 增加查询方式:除了按编号查询,还可以增加按姓名模糊查询。
- 增加排序方式:除了按工资排序,还可以增加按年龄、姓名等排序。
- 改进数据结构:使用链表代替动态数组,链表在频繁的插入和删除操作上效率更高,但随机访问稍慢。
- 用户界面美化:使用颜色代码(Windows的
<windows.h>)或更复杂的控制台库(如ncurses)来美化界面。 - 密码保护:为系统增加登录功能,设置管理员密码。
- 数据验证:在输入时增加更多的数据验证逻辑,例如年龄、工资必须是正数,姓名不能为空等。
- 多文件组织:将代码拆分为多个文件(如
main.c,employee.c,file_io.c,utils.h),使项目结构更清晰,符合大型项目的开发规范。
