员工管理系统

一、基础知识

哈希链表

二、项目文件 & 代码

staff_manage_system目录下

1、Makefile文件

2、include-子目录

3、src-子目录

4、obj-子目录

5、bin-子目录

1、Makefile文件

ALL:
	make -C ./src/
	make -C ./obj/
.PHONY:CLEAN
CLEAN:
	rm obj/*.o
	rm bin/*

2、include-子目录

staff.h

源码
#ifndef STAFF_H
#define STAFF_H
//相关头文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//文件相关头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 50



//相关定义

typedef struct staff{
	char name[20];
	int id;
	char position[20];
	int salary;
	char status[20];
}data_type;

typedef struct linkNode{
	data_type data;
	struct linkNode *pNext;
}Link;

typedef struct hash{
	Link *pArr[SIZE];
	int count;
	int lastId;
}Hash;

typedef enum ret
{
	/* member */
	HASH_NULL = -4,
	MALLOC_ERROR,
	ERROR,
	POS_ERROR,
	OK
} ret_e;



//函数声明

int Menu(void);

Hash *createHash(void);

int hashFun(int key);

int insertHash(Hash *pHash,data_type item);

int showHash(Hash *pHash);

int deleteStaffInformation(Hash *pHash,int id);

int searchStaffInformation(Hash *pHash,int id,data_type *pData);

int modifyStaffInformation(Hash *pHash,data_type NewData);

int Load(Hash *PHash);
#endif
注释
这段代码是一个C语言的头文件(.h文件),主要用于定义与“员工”信息相关的数据结构以及声明一些函数。我会逐行为你解释:

c
#ifndef STAFF_H
这一行是预处理指令,用于检查是否已经定义了STAFF_H。如果没有定义,则编译接下来的代码;如果已经定义,则跳过接下来的代码,直到遇到#endif。这样做是为了防止头文件被多次包含,避免重复定义的问题。

c
#define STAFF_H
定义STAFF_H,这样,如果再次尝试包含这个头文件,由于STAFF_H已经被定义,所以不会再编译此头文件中的内容。

c
//相关头文件
这是一个注释,说明接下来的代码是引入相关的头文件。

c
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>
引入三个标准库头文件,分别为:

stdio.h:用于输入输出。

stdlib.h:包含一些常用函数,如内存分配函数。

string.h:用于字符串操作。

c
//文件相关头文件
注释说明接下来是引入与文件操作相关的头文件。

c
#include<sys/types.h>  
#include<sys/stat.h>  
#include<fcntl.h>
引入三个与文件操作和系统类型定义相关的头文件。

c
#define SIZE 50
定义一个宏SIZE,其值为50。

c
//相关定义
注释说明接下来是相关的数据结构和枚举定义。

c
typedef struct staff{  
	char name[20];  
	int id;  
	char position[20];  
	int salary;  
	char status[20];  
}data_type;
定义了一个结构体staff,用于表示员工的信息。该结构体包含:

name:员工的名字,字符数组,长度为20。
id:员工的ID,整数类型。
position:员工的职位,字符数组,长度为20。
salary:员工的薪水,整数类型。
status:员工的状态,字符数组,长度为20。
然后,使用typedef为这个结构体定义了一个别名data_type。

c
typedef struct linkNode{  
	data_type data;  
	struct linkNode *pNext;  
}Link;
定义了一个单链表节点结构体linkNode,包含一个data_type类型的数据和一个指向下一个节点的指针。然后,使用typedef为这个结构体定义了一个别名Link。

c
typedef struct hash{  
	Link *pArr[SIZE];  
	int count;  
	int lastId;  
}Hash;
定义了一个哈希表结构体hash,包含一个Link指针数组(用于存储链表)、一个整数count(用于记录哈希表中的元素数量)和一个整数lastId(用于记录最后一个分配的ID)。然后,使用typedef为这个结构体定义了一个别名Hash。

c
typedef enum ret{  
	HASH_NULL = -4,  
	MALLOC_ERROR,  
	ERROR,  
	POS_ERROR,  
	OK  
} ret_e;
定义了一个枚举类型ret,用于表示函数的返回值状态。这个枚举类型有一个别名ret_e。

c
//函数声明
注释说明接下来是函数的声明。

以下是一系列的函数声明,它们告诉编译器这些函数的存在,但具体的实现可能在其他.c文件中。

c
int Menu(void);  
Hash *createHash(void);  
int hashFun(int key);  
int insertHash(Hash *pHash,data_type item);  
int showHash(Hash *pHash);  
int deleteStaffInformation(Hash *pHash,int id);  
int searchStaffInformation(Hash *pHash,int id,data_type *pData);  
int modifyStaffInformation(Hash *pHash,data_type NewData);  
int Load(Hash *PHash);
这些函数大致的功能是:

Menu:可能是一个显示菜单的函数。
createHash:创建一个新的哈希表。
hashFun:哈希函数,可能用于计算员工的ID在哈希表中的位置。
insertHash:在哈希表中插入一个员工的信息。
showHash:显示哈希表中的所有员工信息。
deleteStaffInformation:根据ID删除一个员工

3、src-子目录

main.c

源码
#include"../include/staff.h"

int main(int argc, const char *argv[])
{
	int op = 0;
	int ret = 0;
	data_type item;
	int id = 0;
	
	Hash *pHash = createHash();

	data_type staffData;

	while(1){
		op = Menu();	
		if(-1 == op)	break;
		switch(op){
			case 1:
				printf("请输入新员工的姓名:\t");
				scanf("%s",item.name);
				item.id = pHash->lastId + 1;
				pHash->lastId++;
				printf("请输入新员工的职位:\t");
				scanf("%s",item.position);
				printf("请输入新员工的薪资:\t");
				scanf("%d",&item.salary);
				printf("请输入新员工的状态:\t");
				scanf("%s",item.status);
				ret = insertHash(pHash,item);	
				break;

			case 2:
				printf("请输入要开除员工的id号:\t");
				scanf("%d",&id);
				ret = deleteStaffInformation(pHash,id);;
				break;

			case 3:
				printf("请输入所要查询员工的id号:\t");
				scanf("%d",&id);
				ret = searchStaffInformation(pHash,id,NULL);
				break;

			case 4:
				printf("请输入要修改员工信息的id:\t");
				scanf("%d",&id);
				searchStaffInformation(pHash,id,&staffData);
				printf("请输入调整后的岗位:\t");
				scanf("%s",staffData.position);
				printf("请定薪:\t");
				scanf("%d",&staffData.salary);
				ret = modifyStaffInformation(pHash,staffData);
				break;

			case 5:
				ret = showHash(pHash);
				break;

			case 6:
				ret = Save(pHash);
				break;

			case 7:
				ret = Load(pHash);
				break;

			default:
				puts("请输入正确的选项!!!");
				break;
		}
		switch(ret){
		case HASH_NULL:
			puts("HASH_NULL");
			break;
		case MALLOC_ERROR:
			puts("MALLOC_ERROR");
			break;
		case ERROR:
			puts("ERROR");
			break;
		case POS_ERROR:
			puts("POS_ERROR");
			break;
		}
	}
	return 0;
}
注释
以下是对于main函数的详细注释:

c
#include"../include/staff.h" // 引入员工信息相关的头文件  
  
int main(int argc, const char *argv[]) // 主函数入口  
{  
    int op = 0; // 操作选项变量,用于存储用户选择的操作  
    int ret = 0; // 函数返回值变量,用于存储函数执行后的状态  
    data_type item; // 定义一个员工信息结构体变量  
    int id = 0; // 员工ID变量  
  
    // 创建哈希表  
    Hash *pHash = createHash();  
    data_type staffData; // 用于临时存储员工信息的变量  
  
    // 循环显示菜单并等待用户输入操作选项  
    while(1){  
        op = Menu(); // 显示菜单并获取用户选择的操作选项  
  
        if(-1 == op) break; // 如果用户选择退出,则跳出循环  
  
        switch(op){ // 根据用户选择的操作选项执行相应的代码块  
            case 1: // 插入新员工信息  
                printf("请输入新员工的姓名:\t");  
                scanf("%s", item.name);  
                item.id = pHash->lastId + 1; // 新员工的ID为哈希表当前最后一个ID加1  
                pHash->lastId++; // 更新哈希表的最后一个ID  
                printf("请输入新员工的职位:\t");  
                scanf("%s", item.position);  
                printf("请输入新员工的薪资:\t");  
                scanf("%d", &item.salary);  
                printf("请输入新员工的状态:\t");  
                scanf("%s", item.status);  
                ret = insertHash(pHash, item); // 插入新员工信息到哈希表  
                break;  
  
            case 2: // 删除员工信息  
                printf("请输入要开除员工的id号:\t");  
                scanf("%d", &id);  
                ret = deleteStaffInformation(pHash, id); // 根据ID删除员工信息  
                break;  
  
            case 3: // 查询员工信息  
                printf("请输入所要查询员工的id号:\t");  
                scanf("%d", &id);  
                ret = searchStaffInformation(pHash, id, NULL); // 查询员工信息,不需要返回员工数据  
                break;  
  
            case 4: // 修改员工信息  
                printf("请输入要修改员工信息的id:\t");  
                scanf("%d", &id);  
                // 先查询员工信息  
                searchStaffInformation(pHash, id, &staffData);  
                printf("请输入调整后的岗位:\t");  
                scanf("%s", staffData.position);  
                printf("请定薪:\t");  
                scanf("%d", &staffData.salary);  
                ret = modifyStaffInformation(pHash, staffData); // 修改员工信息  
                break;  
  
            case 5: // 显示所有员工信息  
                ret = showHash(pHash); // 显示哈希表中的所有员工信息  
                break;  
  
            case 6: // 保存员工信息到文件  
                ret = Save(pHash); // 保存哈希表到文件  
                break;  
  
            case 7: // 从文件加载员工信息  
                ret = Load(pHash); // 从文件加载员工信息到哈希表  
                break;  
  
            default: // 非法操作选项  
                puts("请输入正确的选项!!!");  
                break;  
        }  
  
        // 根据函数返回值显示错误信息  
        switch(ret){  
            case HASH_NULL:  
                puts("HASH_NULL");  
                break;  
            case MALLOC_ERROR:  
                puts("MALLOC_ERROR");  
                break;  
            case ERROR:  
                puts("ERROR");  
                break;  
            case POS_ERROR:  
                puts("POS_ERROR");  
                break;  
        }  
    }  
  
    return 0; // 程序正常退出  
}
这个main函数是程序的主入口点,它首先创建了一个哈希表来存储员工信息。然后进入一个无限循环,显示菜单并等待用户输入操作选项。根据用户的选择,程序执行相应的操作,如插入新员工、删除员工、查询员工信息、修改员工信息、显示所有员工信息、保存员工信息到文件以及从文件加载员工信息。每个操作都调用相应的函数,并根据函数的返回值来输出可能的错误信息。如果用户选择退出,则跳出循环并结束程序。

需要注意的是,这段代码假设已经有一个Menu函数用于显示菜单并获取用户输入的操作选项,以及一个Save函数用于保存哈希表到文件,这两个函数的具体实现在这段代码中并没有给出。另外,代码中的Save函数和Load函数应该是根据Hash结构体的具体

menu.c

源码
#include"../include/staff.h"
int Menu(void)
{
	int op = 0;
	puts("|--------------------员工管理系统--------------------|");
	puts("| 1-->增加员工信息                                   |");
	puts("| 2-->开除员工                                       |");
	puts("| 3-->查询员工信息                                   |");
	puts("| 4-->修改员工信息                                   |");
	puts("| 5-->显示员工信息                                   |");
	puts("| 6-->保存                                           |");
	puts("| 7-->导入                                           |");
	puts("|-1-->退出系统                                       |");
	puts("|----------------------------------------------------|");
	printf("请输入选项:");
	scanf("%d",&op);
	return op;
}
注释
以下是对于Menu函数的详细注释:

c
#include"../include/staff.h"  //引入员工信息相关的头文件  
  
// Menu函数用于显示菜单并获取用户输入的操作选项  
int Menu(void)  
{  
    int op = 0; // 定义一个整数变量用于存储用户选择的操作选项  
  
    // 输出菜单选项  
    puts("|--------------------员工管理系统--------------------|");  
    puts("| 1-->增加员工信息                                   |");  
    puts("| 2-->开除员工                                       |");  
    puts("| 3-->查询员工信息                                   |");  
    puts("| 4-->修改员工信息                                   |");  
    puts("| 5-->显示员工信息                                   |");  
    puts("| 6-->保存                                           |");  
    puts("| 7-->导入                                           |");  
    puts("|-1-->退出系统                                       |");  
    puts("|----------------------------------------------------|");  
  
    // 提示用户输入选项  
    printf("请输入选项:");  
  
    // 获取用户输入的操作选项  
    scanf("%d", &op);  
  
    // 返回用户选择的操作选项  
    return op;  
}
Menu函数是一个独立的函数,它的主要功能是显示一个包含多个操作选项的菜单,并提示用户输入一个操作选项。用户输入的选项被存储在变量op中,并最终通过return语句返回这个选项。

具体功能如下:

使用puts函数输出菜单的每一行,以创建一个整齐美观的菜单界面。

使用printf函数提示用户输入一个操作选项。

使用scanf函数读取用户输入的整数,并将其存储在变量op中。

返回变量op的值,这个值代表了用户选择的操作选项,可以在调用Menu函数的代码处使用。

需要注意的是,这个函数假设用户会按照提示输入一个合法的整数选项。在实际应用中,可能需要添加一些错误处理机制来确保输入的有效性,比如检查用户是否输入了数字,以及输入的数字是否在菜单选项的范围内。此外,这个函数没有处理scanf可能遇到的输入错误,这在实际应用中也是需要考虑的。

create.c

源码
#include"../include/staff.h"
Hash *createHash(void){
	Hash *pHash = NULL;
	
	pHash = (Hash *)malloc(sizeof(Hash));
	if(!pHash)	return NULL;

	memset(pHash,0,sizeof(Hash));

	return pHash;
	
}

int hashFun(int key){
	return key - 1;
}
注释
以下是对于createHash和hashFun函数的详细注释:


#include"../include/staff.h"  // 引入包含Hash结构定义和相关宏/函数声明的头文件  
  
// createHash函数用于创建一个新的Hash结构体并返回其指针  
Hash *createHash(void) {  
    Hash *pHash = NULL;  // 定义一个Hash类型的指针变量pHash,并初始化为NULL  
  
    // 为pHash动态分配内存,使其指向一个新的Hash结构体  
    pHash = (Hash *)malloc(sizeof(Hash));  
  
    // 检查内存分配是否成功  
    if (!pHash) return NULL;  // 如果内存分配失败,则返回NULL  
  
    // 使用memset函数将新分配的Hash结构体内存区域初始化为0  
    memset(pHash, 0, sizeof(Hash));  
  
    // 返回新创建的Hash结构体的指针  
    return pHash;  
}  
  
// hashFun函数是一个简单的哈希函数,用于将键(key)转换为哈希表中的索引  
int hashFun(int key) {  
    // 此哈希函数简单地将键减去1作为哈希值返回  
    // 注意:这种哈希函数可能不适合所有情况,因为它可能导致哈希冲突  
    // 在实际应用中,应该根据键的特点和哈希表的大小来选择合适的哈希函数  
    return key - 1;  
}
createHash函数的功能是创建一个新的Hash结构体实例,并返回指向这个实例的指针。它首先尝试为Hash结构体分配内存,如果内存分配失败(即malloc返回NULL),则函数返回NULL。如果内存分配成功,它会使用memset函数将新分配的内存区域初始化为0,以确保结构体中的所有字段都被设置为默认值。最后,函数返回指向新创建的Hash结构体的指针。

hashFun函数是一个简单的哈希函数,它接受一个整数键key作为参数,并返回该键经过简单运算后的哈希值。在这个例子中,哈希函数仅仅是将键减去1。这种简单的哈希函数可能不适用于所有情况,因为它可能导致哈希冲突(即不同的键产生相同的哈希值)。在实际应用中,应该根据键的特点和哈希表的大小来选择合适的哈希函数,以减少哈希冲突的可能性。

insert.c

源码
#include"../include/staff.h"
int insertHash(Hash *pHash,data_type item){
	if(NULL == pHash)
	{
		return HASH_NULL;
	}

	int index = hashFun(item.id);

	Link *pNew = (Link *)malloc(sizeof(Link));
	if(NULL == pNew)
	{
		return MALLOC_ERROR;
	}

	memset(pNew,0,sizeof(Link));

	pNew->data = item;

	pNew->pNext = pHash->pArr[index];

	pHash->pArr[index] = pNew;

	pHash->count++;

	return OK;
}
注释
以下是insertHash函数的详细注释:

c
#include"../include/staff.h"  // 引入员工管理系统的头文件,其中定义了Hash结构、data_type、Link结构、以及相关的宏和函数  
  
// insertHash函数用于向哈希表中插入一个元素  
int insertHash(Hash *pHash, data_type item) {  
  
    // 检查传入的哈希表指针是否为空  
    if (NULL == pHash) {  
        // 如果为空,则返回错误码HASH_NULL  
        return HASH_NULL;  
    }  
  
    // 计算元素的哈希值,确定元素在哈希表中的索引位置  
    int index = hashFun(item.id);  
  
    // 为新节点分配内存  
    Link *pNew = (Link *)malloc(sizeof(Link));  
    if (NULL == pNew) {  
        // 如果内存分配失败,则返回错误码MALLOC_ERROR  
        return MALLOC_ERROR;  
    }  
  
    // 将新分配的内存区域初始化为0  
    memset(pNew, 0, sizeof(Link));  
  
    // 将要插入的元素赋值给新节点的data字段  
    pNew->data = item;  
  
    // 将新节点插入到哈希表的指定位置,新节点指向原来该位置的头节点  
    pNew->pNext = pHash->pArr[index];  
  
    // 更新哈希表指定位置的头节点为新节点  
    pHash->pArr[index] = pNew;  
  
    // 哈希表中元素数量加1  
    pHash->count++;  
  
    // 插入成功,返回OK  
    return OK;  
}
函数insertHash的主要功能是将一个data_type类型的元素item插入到哈希表pHash中。

首先,函数检查传入的哈希表指针pHash是否为空,如果为空则返回错误码HASH_NULL。

接着,使用hashFun函数计算item的哈希值,从而确定它在哈希表中的索引位置index。

然后,为新节点分配内存,如果内存分配失败则返回错误码MALLOC_ERROR。

使用memset函数将新分配的内存区域初始化为0,确保新节点是干净的。

将要插入的元素item赋值给新节点的data字段。

新节点插入到哈希表的指定位置index,新节点的pNext指针指向原来该位置的头节点,完成链表的头插操作。

更新哈希表在位置index的头节点为新节点。

哈希表中元素数量增加1,更新count字段。

最后,函数返回OK表示插入成功。

注意:

data_type、Hash、Link、HASH_NULL、MALLOC_ERROR、OK等应该在staff.h头文件中有所定义,它们可能是结构体、类型别名、宏或常量。
函数假设hashFun能够返回一个有效的索引值,并且这个索引值在哈希表的数组范围内。
函数没有处理哈希冲突,它只是简单地将新节点插入到哈希表的对应位置链表的头部。在实际应用中,可能需要更复杂的策略来处理哈希冲突,如链地址法、开放寻址法等。
函数没有进行边界检查,如检查index是否越界。在实际应用中,应该添加适当的边界检查来提高代码的健壮性。

show.c

源码
#include"../include/staff.h"
int showHash(Hash *pHash){
	if(NULL == pHash)
	{
		return HASH_NULL;
	}

	int i;
	Link *pTmp = NULL;
	for(i = 0; i < pHash->lastId; i++){
		pTmp = pHash->pArr[i];

		while(NULL != pTmp){
			printf("|----------员工信息----------|\n");
			printf("|姓名:%s            \n",pTmp->data.name);
			printf("|工号:%d            \n",pTmp->data.id);
			printf("|职位:%s            \n",pTmp->data.position);
			printf("|薪资:%d            \n",pTmp->data.salary);
			printf("|状态:%s            \n",pTmp->data.status);
			printf("|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|\n");
			pTmp = pTmp->pNext;
		}
	}
	return OK;
}
注释
c
#include"../include/staff.h"  // 引入员工管理系统的头文件,其中定义了Hash结构、Link结构、data_type类型以及相关的宏和函数  
  
// showHash函数用于展示哈希表中所有员工的信息  
int showHash(Hash *pHash) {  
    // 检查传入的哈希表指针是否为空  
    if (NULL == pHash) {  
        // 如果为空,则返回错误码HASH_NULL  
        return HASH_NULL;  
    }  
  
    // 遍历哈希表的每个位置  
    int i;  
    Link *pTmp = NULL;  
    for (i = 0; i < pHash->lastId; i++) {  
        // 获取当前位置的头节点  
        pTmp = pHash->pArr[i];  
  
        // 遍历当前位置的链表,展示每个员工的信息  
        while (NULL != pTmp) {  
            // 打印员工信息的分隔线  
            printf("|----------员工信息----------|\n");  
  
            // 打印员工的姓名  
            printf("|姓名:%s            \n", pTmp->data.name);  
  
            // 打印员工的工号  
            printf("|工号:%d            \n", pTmp->data.id);  
  
            // 打印员工的职位  
            printf("|职位:%s            \n", pTmp->data.position);  
  
            // 打印员工的薪资  
            printf("|薪资:%d            \n", pTmp->data.salary);  
  
            // 打印员工的状态  
            printf("|状态:%s            \n", pTmp->data.status);  
  
            // 打印员工信息的分隔线  
            printf("|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|\n");  
  
            // 移动到下一个节点  
            pTmp = pTmp->pNext;  
        }  
    }  
  
    // 展示成功,返回OK  
    return OK;  
}
函数showHash的主要功能是遍历哈希表,并打印出哈希表中每个员工的信息。

函数首先检查传入的哈希表指针pHash是否为空,如果为空则返回错误码HASH_NULL。

然后,使用循环遍历哈希表的每个位置,lastId是哈希表最后一个有效位置的索引加1,它表示哈希表的大小。

对于每个位置,函数获取该位置的头节点pTmp,并遍历该位置的链表。

在遍历链表的过程中,函数使用printf函数打印出每个员工的姓名、工号、职位、薪资和状态。

链表遍历完成后,函数继续遍历哈希表的下一个位置,直到遍历完所有的位置。

最后,函数返回OK,表示员工信息展示成功。

注意:

data_type应该在staff.h头文件中定义,它包含了员工的姓名、工号、职位、薪资和状态等字段。
Hash和Link结构也应在staff.h中定义,其中Hash结构包含了指向各个链表头节点的数组pArr以及表示哈希表大小的lastId等字段,Link结构则定义了链表节点的结构。
HASH_NULL和OK应该是预定义的宏或常量,用于表示不同的错误或成功状态。
函数假设哈希表已经被正确初始化,并且lastId的值反映了哈希表的实际大小。
函数没有处理任何错误情况,如哈希表损坏或链表节点损坏等。在实际应用中,应该添加适当的错误处理机制以提高代码的健壮性。

delete.c

源码
#include"../include/staff.h"
int deleteStaffInformation(Hash *pHash,int id){
	if(!pHash)	return HASH_NULL;

	if(id < 0 || id > pHash->lastId)	return POS_ERROR;

	int pos = hashFun(id);

	Link *pHead = pHash->pArr[pos];
	if(NULL == pHead)	return	POS_ERROR;

	while(pHash != NULL){
		if(id == pHead->data.id){
			pHash->count--;
			strcpy(pHead->data.status,"已离职");
			break;
		}
		pHead = pHead->pNext;
	}
	return OK;
}
注释
c
#include"../include/staff.h"  // 引入员工管理系统的头文件,其中包含Hash、Link、data_type的定义,以及相关的函数和宏  
  
// deleteStaffInformation函数用于删除哈希表中指定工号的员工信息,将员工状态标记为"已离职"  
int deleteStaffInformation(Hash *pHash, int id) {  
    // 检查哈希表指针是否为空  
    if (!pHash) return HASH_NULL;  // 如果为空,返回错误码HASH_NULL  
  
    // 检查员工工号是否在合法范围内  
    if (id < 0 || id > pHash->lastId) return POS_ERROR;  // 如果不在合法范围内,返回错误码POS_ERROR  
  
    // 计算工号对应的哈希位置  
    int pos = hashFun(id);  
  
    // 获取哈希位置的头节点  
    Link *pHead = pHash->pArr[pos];  
  
    // 检查头节点是否为空  
    if (NULL == pHead) return POS_ERROR;  // 如果为空,返回错误码POS_ERROR  
  
    // 遍历链表,查找指定工号的员工  
    while (pHead != NULL) {  // 注意:原代码中的while条件判断有误,应该是判断pHead而非pHash  
        // 如果找到指定工号的员工  
        if (id == pHead->data.id) {  
            // 哈希表中员工数量减一  
            pHash->count--;  
  
            // 将员工状态修改为"已离职"  
            strcpy(pHead->data.status, "已离职");  
  
            // 找到并修改状态后,跳出循环  
            break;  
        }  
  
        // 移动到下一个节点  
        pHead = pHead->pNext;  
    }  
  
    // 如果没有找到指定工号的员工,但代码没有返回错误,这里可能需要添加检查逻辑  
    // (例如,检查pHead是否为NULL,若为NULL则表示未找到,应返回错误码)  
  
    // 删除成功,返回OK  
    return OK;  
}
详细注释解释:

函数deleteStaffInformation接收一个指向Hash结构体的指针pHash和一个整数id作为参数,用于删除哈希表中指定工号的员工信息。

首先检查pHash是否为空,如果为空则返回错误码HASH_NULL。

接着检查工号id是否在合法范围内,即是否在0到pHash->lastId之间。如果不在范围内,则返回错误码POS_ERROR。

使用hashFun函数计算工号id对应的哈希位置pos。

获取哈希位置pos的头节点pHead。

检查头节点pHead是否为空,如果为空则返回错误码POS_ERROR。

使用while循环遍历链表,查找工号为id的员工。注意:原代码中的while循环条件判断错误,应该判断pHead是否为空,而不是pHash。

如果找到指定工号的员工,则将哈希表中的员工数量减一,并将该员工的状态字段status修改为"已离职"。

修改完状态后,跳出循环。

需要注意的是,如果未找到指定工号的员工,原代码没有返回错误码,可能需要在循环结束后添加检查逻辑,例如检查pHead是否为NULL,如果为NULL则表示未找到员工,应返回错误码。

最后,如果成功找到并修改了员工状态,则返回OK表示删除成功。

注意:在实际应用中,标记员工为"已离职"可能并不算是真正的"删除"操作,因为员工的信息仍然保留在哈希表中。如果需要完全删除员工信息,可能需要重新设计函数,考虑如何从哈希表和链表中移除节点。此外,对哈希表的修改操作应该考虑线程安全问题,避免并发访问时发生数据冲突。

search.c

源码
#include"../include/staff.h"
int searchStaffInformation(Hash *pHash,int id,data_type *pData){
	if(!pHash)	return HASH_NULL;

	if(id < 0 || id > pHash->lastId)	return POS_ERROR;

	int pos = hashFun(id);

	Link * pHead = pHash->pArr[pos];

	if(!pHead)	return POS_ERROR;

	while(pHead != NULL){
		if(id == pHead->data.id){
			if(NULL == pData){
				printf("|----------员工信息----------|\n");
				printf("|姓名:%s            \n",pHead->data.name);
				printf("|工号:%d            \n",pHead->data.id);
				printf("|职位:%s            \n",pHead->data.position);
				printf("|薪资:%d            \n",pHead->data.salary);
				printf("|状态:%s            \n",pHead->data.status);
				printf("|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|\n");
			}else{
				*pData = pHead->data;
			}
			return OK;
		}
		pHead = pHead->pNext;
	}
	return OK;
}
注释
c
#include"../include/staff.h"  // 引入员工管理系统的头文件  
  
// searchStaffInformation函数用于在哈希表中搜索指定工号的员工信息  
int searchStaffInformation(Hash *pHash, int id, data_type *pData) {  
    // 检查哈希表指针是否为空  
    if (!pHash) return HASH_NULL;  // 如果为空,返回错误码HASH_NULL  
  
    // 检查工号是否在合法范围内  
    if (id < 0 || id > pHash->lastId) return POS_ERROR;  // 如果不在合法范围内,返回错误码POS_ERROR  
  
    // 计算工号对应的哈希位置  
    int pos = hashFun(id);  
  
    // 获取哈希位置的头节点  
    Link *pHead = pHash->pArr[pos];  
  
    // 检查头节点是否为空  
    if (!pHead) return POS_ERROR;  // 如果为空,返回错误码POS_ERROR  
  
    // 遍历链表,查找指定工号的员工  
    while (pHead != NULL) {  
        // 如果找到指定工号的员工  
        if (id == pHead->data.id) {  
            // 根据pData是否为NULL,决定是直接打印信息还是返回数据  
            if (NULL == pData) {  
                // 打印员工信息  
                printf("|----------员工信息----------|\n");  
                printf("|姓名:%s            \n", pHead->data.name);  
                printf("|工号:%d            \n", pHead->data.id);  
                printf("|职位:%s            \n", pHead->data.position);  
                printf("|薪资:%d            \n", pHead->data.salary);  
                printf("|状态:%s            \n", pHead->data.status);  
                printf("|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|\n");  
            } else {  
                // 将员工数据赋值给pData指针指向的变量  
                *pData = pHead->data;  
            }  
  
            // 找到员工信息,返回OK  
            return OK;  
        }  
  
        // 移动到下一个节点  
        pHead = pHead->pNext;  
    }  
  
    // 如果未找到指定工号的员工,原代码错误地返回了OK  
    // 正确的做法应该是返回表示未找到的错误码,例如POS_ERROR  
    return POS_ERROR;  // 未找到员工,返回错误码POS_ERROR  
}
详细注释解释:

函数searchStaffInformation接收一个指向Hash结构体的指针pHash、一个整数id和一个指向data_type的指针pData作为参数。函数用于在哈希表中搜索指定工号的员工信息,并将信息打印或赋值给pData。

检查pHash是否为空,如果为空则返回错误码HASH_NULL。

检查工号id是否在合法范围内,即是否在0到pHash->lastId之间。如果不在范围内,返回错误码POS_ERROR。

使用hashFun函数计算id对应的哈希位置pos。

获取哈希位置pos的头节点pHead。

检查头节点pHead是否为空,如果为空则返回错误码POS_ERROR。

使用while循环遍历链表,查找工号为id的员工。

如果找到指定工号的员工,根据pData是否为NULL,决定是直接打印员工信息还是将信息赋值给pData指向的变量。

打印员工信息时,使用printf函数输出员工的姓名、工号、职位、薪资和状态。

将员工信息赋值给pData时,使用*pData = pHead->data。

找到员工信息后,返回OK。

注意:原代码中在循环结束后返回了OK,这是不正确的。如果循环结束仍未找到员工,应返回表示未找到的错误码,例如POS_ERROR。

修改了循环结束后的返回值,如果未找到员工,则返回POS_ERROR。

在实际应用中,还需要考虑pData指针的有效性,以避免可能的空指针解引用错误。此外,对于函数返回值的处理,应根据具体需求进行调整,以确保调用者能够正确处理各种情况。

modify.c

源码
#include"../include/staff.h"
int modifyStaffInformation(Hash *pHash,data_type NewData){
	if(!pHash)	return HASH_NULL;

	int pos = hashFun(NewData.id);

	Link *pHead = pHash->pArr[pos];

	if(!pHead)	return POS_ERROR;

	while(pHead != NULL){
		if(NewData.id == pHead->data.id){
			pHead->data = NewData;
		}
		pHead = pHead->pNext;
	}
	return OK;
}
注释
c
#include"../include/staff.h"  // 引入员工管理系统的头文件,包含Hash、Link、data_type的定义,以及相关的函数和宏  
  
// modifyStaffInformation函数用于修改哈希表中指定工号的员工信息  
int modifyStaffInformation(Hash *pHash, data_type NewData) {  
    // 检查哈希表指针是否为空  
    if (!pHash) return HASH_NULL;  // 如果为空,返回错误码HASH_NULL  
  
    // 计算新数据对应的哈希位置  
    int pos = hashFun(NewData.id);  
  
    // 获取哈希位置的头节点  
    Link *pHead = pHash->pArr[pos];  
  
    // 检查头节点是否为空  
    if (!pHead) return POS_ERROR;  // 如果为空,返回错误码POS_ERROR  
  
    // 遍历链表,查找指定工号的员工  
    while (pHead != NULL) {  
        // 如果找到指定工号的员工  
        if (NewData.id == pHead->data.id) {  
            // 用新数据覆盖旧数据  
            pHead->data = NewData;  
  
            // 修改成功,可以跳出循环  
            break;  
        }  
  
        // 移动到下一个节点  
        pHead = pHead->pNext;  
    }  
  
    // 注意:如果未找到指定工号的员工,函数仍然返回OK,这可能不是预期的行为  
    // 实际应用中,可能需要检查pHead是否为NULL,并在未找到员工时返回错误码  
  
    // 修改成功,返回OK  
    return OK;  
}
详细注释解释:

函数modifyStaffInformation接收一个指向Hash结构体的指针pHash和一个data_type类型的变量NewData作为参数,用于修改哈希表中指定工号的员工信息。

首先检查pHash是否为空,如果为空则返回错误码HASH_NULL。

使用hashFun函数计算NewData中的工号id对应的哈希位置pos。

根据哈希位置pos,从哈希表的数组中获取对应的头节点pHead。

检查头节点pHead是否为空,如果为空则返回错误码POS_ERROR。

使用while循环遍历链表,查找工号为NewData.id的员工。

如果找到指定工号的员工,则使用新数据NewData覆盖旧数据pHead->data。

修改成功后,可以跳出循环。

需要注意的是,如果未找到指定工号的员工,原代码没有返回错误码,而是继续执行并返回OK。在实际应用中,可能需要检查pHead是否为NULL,并在未找到员工时返回错误码。

最后,如果成功修改了员工信息,则返回OK表示修改成功。

请注意,在实际应用中,修改员工信息可能涉及更多的逻辑,例如验证新数据的合法性、更新哈希表的计数等。此外,还需要考虑线程安全性和并发访问的问题。在设计和实现此类功能时,应仔细考虑这些方面以确保系统的正确性和稳定性。

save.c

源码
#include"../include/staff.h"
int Save(Hash *pHash){
	int fw = open("staffInformation.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);

	if(fw < 0)	perror("open error");
		else{
		
			int i;
			for(i = 0; i < pHash->lastId; i++){
				Link *pTmp = pHash->pArr[i];
				while(NULL != pTmp){
					int wr_count = write(fw,&pTmp->data,sizeof(data_type));
					if(0 == wr_count){
						puts("未成功写入!");
						break;
					}else if(wr_count < 0){
						perror("写入失败");
						break;
					}
					pTmp = pTmp->pNext;
				}
			}
			close(fw);
		}
}
注释
c
#include"../include/staff.h"  
  
// Save函数用于将哈希表中的数据保存到文件"staffInformation.txt"中  
int Save(Hash *pHash) {  
    // 使用open函数以只写、创建、截断方式打开文件,并设置权限为0664  
    int fw = open("staffInformation.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);  
  
    // 检查文件是否成功打开  
    if (fw < 0) {  
        // 如果打开失败,打印错误信息  
        perror("open error");  
        return -1;  // 返回错误码  
    } else {  
        int i;  
  
        // 遍历哈希表的每个位置  
        for (i = 0; i < pHash->lastId; i++) {  
            // 获取当前位置的链表头节点  
            Link *pTmp = pHash->pArr[i];  
  
            // 遍历链表  
            while (NULL != pTmp) {  
                // 写入链表节点的数据到文件  
                int wr_count = write(fw, &pTmp->data, sizeof(data_type));  
  
                // 检查写入结果  
                if (0 == wr_count) {  
                    // 如果写入字节数为0,表示未成功写入  
                    puts("未成功写入!");  
                    break;  
                } else if (wr_count < 0) {  
                    // 如果写入失败,打印错误信息  
                    perror("写入失败");  
                    break;  
                }  
  
                // 移动到下一个链表节点  
                pTmp = pTmp->pNext;  
            }  
        }  
  
        // 关闭文件  
        close(fw);  
    }  
  
    return 0;  // 成功保存,返回0  
}
详细注释解释:

Save函数用于将Hash结构体中的员工信息保存到名为staffInformation.txt的文件中。

使用open函数打开文件,并设置文件打开模式为O_WRONLY | O_CREAT | O_TRUNC,这意味着文件以只写方式打开,如果文件不存在则创建它,如果文件已存在则清空文件内容。同时设置文件权限为0664。

检查open函数的返回值fw,如果fw小于0,则表示文件打开失败,使用perror函数打印出系统提供的错误信息。

如果文件成功打开,则使用for循环遍历哈希表的每个位置(由pHash->lastId确定哈希表的大小)。

对于每个位置,获取该位置的链表头节点pTmp。

使用while循环遍历链表,直到链表末尾(pTmp为NULL)。

在循环内部,使用write函数将链表节点的数据(pTmp->data)写入文件。sizeof(data_type)确保写入的数据大小正确。

检查write函数的返回值wr_count。如果返回值为0,表示没有数据被写入,打印提示信息“未成功写入!”。如果返回值为负数,表示写入失败,使用perror函数打印错误信息。

如果写入成功,则将pTmp指针移动到链表的下一个节点,继续写入操作。

遍历完所有链表节点后,关闭文件。

如果整个保存过程成功完成,函数返回0。如果文件打开失败,则函数返回-1。

请注意,这段代码没有考虑多线程或并发访问文件的情况,也没有处理文件写入可能发生的边界情况(如磁盘空间不足)。在实际应用中,这些情况都应该被妥善处理。此外,代码没有包含错误处理逻辑来确保所有写入操作完成后才关闭文件,这在实际应用中也是非常重要的。

load.c

源码
#include"../include/staff.h"
int Load(Hash *pHash){
	data_type messageData;
	int fr = open("staffInformation.txt",O_RDONLY);
	if(fr < 0)	perror("open error");
		else{
			puts("打开员工信息系统成功!");

			while(1){
				int rd_count = read(fr,&messageData,sizeof(data_type));
				if(0 == rd_count){
					puts("导入信息完毕!");
					break;
				}else if(rd_count < 0){
					perror("导入失败");
					return ERROR;
				}else{
					insertHash(pHash,messageData);
					pHash->lastId++;
				}
			}
			close(fr);
		}
}
注释
c
#include"../include/staff.h"  
  
// Load函数用于从文件"staffInformation.txt"中加载员工信息到哈希表pHash中  
int Load(Hash *pHash) {  
    data_type messageData; // 定义一个data_type类型的变量,用于存储从文件中读取的员工信息  
  
    // 使用open函数以只读方式打开文件  
    int fr = open("staffInformation.txt", O_RDONLY);  
  
    // 检查文件是否成功打开  
    if (fr < 0) {  
        // 如果打开失败,打印错误信息  
        perror("open error");  
        return ERROR;  // 返回错误码  
    } else {  
        // 打印成功打开文件的提示信息  
        puts("打开员工信息系统成功!");  
  
        // 使用无限循环读取文件中的数据,直到文件结束或发生错误  
        while (1) {  
            // 从文件中读取数据到messageData变量中  
            int rd_count = read(fr, &messageData, sizeof(data_type));  
  
            // 检查读取结果  
            if (0 == rd_count) {  
                // 如果读取字节数为0,表示文件读取完毕  
                puts("导入信息完毕!");  
                break;  // 跳出循环  
            } else if (rd_count < 0) {  
                // 如果读取失败,打印错误信息  
                perror("导入失败");  
                close(fr);  // 关闭文件  
                return ERROR;  // 返回错误码  
            } else {  
                // 如果读取成功,将读取到的员工信息插入到哈希表中  
                insertHash(pHash, messageData);  
  
                // 更新哈希表的lastId值,表示有新的员工信息被添加  
                pHash->lastId++;  
            }  
        }  
  
        // 关闭文件  
        close(fr);  
    }  
  
    return SUCCESS;  // 导入成功,返回成功码  
}
详细注释解释:

Load函数用于从文件staffInformation.txt中读取员工信息,并将这些信息加载到Hash结构体所表示的哈希表中。

定义了一个data_type类型的变量messageData,用于存储从文件中读取的每一条员工信息。

使用open函数以只读方式打开staffInformation.txt文件,并将文件描述符保存在变量fr中。

检查open函数的返回值fr,如果小于0,则表示文件打开失败,调用perror函数打印错误信息,并返回错误码ERROR。

如果文件成功打开,则打印成功打开文件的提示信息。

使用一个无限循环来不断读取文件中的数据。每次循环调用read函数从文件中读取sizeof(data_type)大小的数据到messageData变量中。

检查read函数的返回值rd_count。如果返回值为0,表示文件已经读取完毕,打印导入完成的提示信息,并跳出循环。

如果rd_count小于0,表示读取文件时发生错误,调用perror函数打印错误信息,关闭文件,并返回错误码ERROR。

如果rd_count大于0,表示成功读取到数据,调用insertHash函数将读取到的员工信息插入到哈希表中,并更新哈希表的lastId值。

循环结束后,关闭文件描述符fr。

如果整个加载过程成功完成,函数返回成功码SUCCESS。

注意:

在这个函数中,假设insertHash函数能够正确处理插入操作,并且Hash结构体已经正确初始化。
ERROR和SUCCESS是预定义的宏或者常量,用于表示操作成功或失败的状态。
文件读取和哈希表插入操作之间没有错误处理逻辑,例如检查insertHash函数的返回值。在实际应用中,应该对这些操作进行错误检查和处理,以确保程序的健壮性。
文件读取完毕后没有显式检查pHash->lastId是否超出了哈希表的实际容量,这在实际应用中也是需要考虑的。

Makefile

ALL:../obj/main.o ../obj/menu.o ../obj/create.o \
	../obj/insert.o ../obj/show.o ../obj/delete.o \
	../obj/search.o	../obj/modify.o ../obj/save.o \
	../obj/load.o

../obj/main.o:main.c
	gcc -c $< -o $@
../obj/menu.o:menu.c
	gcc -c $< -o $@
../obj/create.o:create.c
	gcc -c $< -o $@
../obj/insert.o:insert.c
	gcc -c $< -o $@
../obj/show.o:show.c
	gcc -c $< -o $@
../obj/delete.o:delete.c
	gcc -c $< -o $@
../obj/search.o:search.c
	gcc -c $< -o $@
../obj/modify.o:modify.c
	gcc -c $< -o $@
../obj/save.o:save.c
	gcc -c $< -o $@
../obj/load.o:load.c
	gcc -c $< -o $@

4、obj-子目录

Makefile

ALL:
	gcc *.o -o ../bin/App

5、bin-子目录

执行文件 App

三、项目代码待优化项:

1、modify.c文件
如果修改不存在的员工的信息,程序会段错误
2、待更新……

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值