概述:在上一篇博客中,简单封装了key为int类型的哈希表的增删,遍历等函数,但是在上一篇封装中,函数均是可见的,可能并不安全,所以这一次就将函数封装到结构体,像使用c++一样,直接通过结构体就可以运行函数。所有函数操作都是静态的,这样操作更加方便快捷。此次封装了key为int, char[],char * , void *四种类型的哈希表结构。在多线程中,依旧是不安全的,后期有时间会加入互斥锁,读写锁到里面,用于多线程。
1,这里就说一下key类型为char []的封装,先看.h文件,先封装一个hash的结构体,再定义一个hash控制结构体,将操作函数放在hash控制结构体,同时将hash的结构体也放入hash控制结构体。
#ifndef _SKY_HASH_H_
#define _SKY_HASH_H_
#include <stdlib.h>
#include "uthash.h"
#define KEY_ARR_SIZE 16
typedef struct hash_arr hash_arr_t;
typedef void (*hash_arr_cb_t)(hash_arr_t *, void *);
/*key 为char[]类型结构体封装*/
typedef hash_arr_t *(*hash_arr_find_t)(hash_arr_t **, char *);
typedef int (*hash_arr_add_t)(hash_arr_t **, char *, void *);
typedef int (*hash_arr_del_t)(hash_arr_t **, char *);
typedef void (*hash_arr_delall_t)(hash_arr_t **);
typedef int (*hash_arr_count_t)(hash_arr_t **);
typedef void (*hash_arr_ergodic_t)(hash_arr_t **, hash_arr_cb_t, void *);
typedef struct hash_arr_ctl hash_arr_ctl_t;
struct hash_arr {
char key[KEY_ARR_SIZE]; /* key */
void *data; /*数据*/
UT_hash_handle hh; /* makes this structure hashable */
};
struct hash_arr_ctl {
hash_arr_t *hash;
hash_arr_find_t find;
hash_arr_add_t add;
hash_arr_del_t del;
hash_arr_delall_t delall;
hash_arr_count_t count;
hash_arr_ergodic_t ergodic;
};
/*char []类型key相关操作函数*/
void hash_arr_create(hash_arr_ctl_t *ha);
2,我们再看一下sky_hash.c文件,这个就没啥了,主要就是uthash的函数使用及简单封装,看uthash操作手册就可以看懂了。
#include <stdio.h>
#include <stdlib.h>
#include "uthash.h"
#include "sky_hash.h"
/*****************************************************************************
下方封装key为char []类型的增删,遍历等操作。
By Sky(Peace&Love)
******************************************************************************/
/*查找键值*/
hash_arr_t *hash_arr_find(hash_arr_t **hashlist, char key[])
{
hash_arr_t *hd = NULL;
HASH_FIND_STR(*hashlist,key,hd);
return hd;
}
/*添加键值对*/
int hash_arr_add(hash_arr_t **hashlist, char key[], void *data)
{
hash_arr_t *hd = hash_arr_find(hashlist,key);
if (NULL == hd) {
hd = (hash_arr_t *)malloc(sizeof(hash_arr_t));
strncpy(hd->key,key,KEY_ARR_SIZE);
hd->data = data;
HASH_ADD_STR(*hashlist,key,hd);
} else {
return -1;
}
return 0;
}
/*删除指定键值对*/
static int hash_arr_del(hash_arr_t **hashlist, char key[])
{
hash_arr_t *hd = hash_arr_find(hashlist,key);
if (NULL == hd) {
return -1;
}
HASH_DEL(*hashlist, hd);
if (NULL != hd->data) {
free(hd->data);
hd->data = NULL;
}
free(hd);
hd = NULL;
return 0;
}
/*删除所有键值对*/
static void hash_arr_delall(hash_arr_t **hashlist)
{
hash_arr_t *hd,*tmp;
HASH_ITER(hh, *hashlist, hd, tmp) {
HASH_DEL(*hashlist, hd);
if (NULL != hd->data) {
free(hd->data);
hd->data = NULL;
}
free(hd);
hd = NULL;
}
if (NULL != *hashlist) {
free(*hashlist);
*hashlist = NULL;
}
}
/*遍历哈希表*/
static void hash_arr_ergodic(hash_arr_t **hashlist, hash_arr_cb_t callback, void *arg)
{
hash_arr_t *hd,*tmp;
HASH_ITER(hh, *hashlist, hd, tmp) {
callback(hd,arg);
}
}
/*获取哈希表项目个数*/
static int hash_arr_count(hash_arr_t **hashlist)
{
return HASH_COUNT(*hashlist);
}
/*key为char []类型的哈希表创建初始化*/
void hash_arr_create(hash_arr_ctl_t *ha)
{
ha->hash = NULL;
ha->find = hash_arr_find;
ha->add = hash_arr_add;
ha->del = hash_arr_del;
ha->delall = hash_arr_delall;
ha->count = hash_arr_count;
ha->ergodic = hash_arr_ergodic;
}
3,我们做一个测试程序,验证封装函数的正确性。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "./hash/sky_hash.h"
typedef struct sky sky_t;
/*只做测试使用,可以自定义*/
struct sky {
int num;
/*用户可以自己再增加字段*/
};
void callback_keyarr(hash_arr_t *hd, void *arg)
{
sky_t *value = hd->data;
printf("key:%s,num:%d\n",hd->key,value->num);
}
void test_keyarr()
{
hash_arr_ctl_t *ha = (hash_arr_ctl_t *)malloc(sizeof(hash_arr_ctl_t));
hash_arr_create(ha);
char *key[] = {"bboy","born","sky","peace","love"};
int i;
/*哈希表中添加数据*/
for (i = 0 ; i < 5 ; i ++) {
sky_t *value = (sky_t *)malloc(sizeof(sky_t));
value->num = i;
if (0 != ha->add(&ha->hash,key[i],value)) {
printf("hash add failed\n");
free(value);
}
}
printf("ha:%p\n",ha->hash);
/*遍历哈希表*/
ha->ergodic(&ha->hash,callback_keyarr,NULL);
/*获取哈希表项目个数*/
int count = ha->count(&ha->hash);
printf("hash count:%d\n",count);
/*查找哈希表*/
char fkey[16] = {0};
char *bb = "born";
memcpy(fkey,bb,5);
hash_arr_t *node = ha->find(&ha->hash,fkey);
if (NULL != node) {
sky_t *value = node->data;
printf("find key[born] value num = %d\n",value->num);
/*修改key对应的数据值*/
value->num = 100;
} else {
printf("not found\n");
}
/*删除指定项目*/
ha->del(&ha->hash,"bboy");
/*遍历哈希表*/
ha->ergodic(&ha->hash,callback_keyarr,NULL);
/*删除整个哈希表*/
ha->delall(&ha->hash);
printf("ha:%p\n",ha->hash);
free(ha);
}
int main()
{
test_keyarr();
return 0;
}
4,运行结果如下:
5,所有代码传到码云,develop分支。需要的话可以看下。地址在上一篇有。