4_09_GLib库入门与实践_哈希表

本文深入解析了Glib库中的GHashTable,包括创建、插入、替换、删除、查找、遍历、引用计数和迭代器等操作,并通过示例代码展示了各种功能的使用方法,帮助理解GHashTable在内存管理上的特性。
摘要由CSDN通过智能技术生成

简介

Hash是一种常见的数据结构,GLib提供了操作Hash表的多种操作函数。

数据结构

Hash表有两个重要的数据结构,GHashTable和GHashTableIter,这两者都是不透明的数据结构,可以整体使用它,但无法单独使用其中的一个结构体成员。GHashTable是Hash表本身相关,GHashTableIter与迭代器相关,用来遍历或操作Hash表中的数据。
Hash表:

typedef struct _GHashTable GHashTable;

迭代器:

typedef struct _GHashTableIter GHashTableIter;

函数列表

GHashTable * 	g_hash_table_new ()
GHashTable * 	g_hash_table_new_full ()
guint 	(*GHashFunc) ()
gboolean 	(*GEqualFunc) ()
gboolean 	g_hash_table_insert ()
gboolean 	g_hash_table_replace ()
gboolean 	g_hash_table_add ()
gboolean 	g_hash_table_contains ()
guint 	g_hash_table_size ()
gpointer 	g_hash_table_lookup ()
gboolean 	g_hash_table_lookup_extended ()
void 	g_hash_table_foreach ()
gpointer 	g_hash_table_find ()
void 	(*GHFunc) ()
gboolean 	g_hash_table_remove ()
gboolean 	g_hash_table_steal ()
guint 	g_hash_table_foreach_remove ()
guint 	g_hash_table_foreach_steal ()
void 	g_hash_table_remove_all ()
void 	g_hash_table_steal_all ()
GList * 	g_hash_table_get_keys ()
GList * 	g_hash_table_get_values ()
gpointer * 	g_hash_table_get_keys_as_array ()
gboolean 	(*GHRFunc) ()
#define 	g_hash_table_freeze()
#define 	g_hash_table_thaw()
void 	g_hash_table_destroy ()
GHashTable * 	g_hash_table_ref ()
void 	g_hash_table_unref ()
void 	g_hash_table_iter_init ()
gboolean 	g_hash_table_iter_next ()
GHashTable * 	g_hash_table_iter_get_hash_table ()
void 	g_hash_table_iter_replace ()
void 	g_hash_table_iter_remove ()
void 	g_hash_table_iter_steal ()
gboolean 	g_direct_equal ()
guint 	g_direct_hash ()
gboolean 	g_int_equal ()
guint 	g_int_hash ()
gboolean 	g_int64_equal ()
guint 	g_int64_hash ()
gboolean 	g_double_equal ()
guint 	g_double_hash ()
gboolean 	g_str_equal ()
guint 	g_str_hash ()

函数功能分类

创建

GHashTable * 	g_hash_table_new ()
GHashTable * 	g_hash_table_new_full ()

销毁

void 	g_hash_table_destroy ()

插入

gboolean 	g_hash_table_insert ()
gboolean 	g_hash_table_add ()

替换

gboolean 	g_hash_table_replace ()

删除

gboolean 	g_hash_table_remove ()
gboolean 	g_hash_table_steal ()
guint 	g_hash_table_foreach_remove ()
guint 	g_hash_table_foreach_steal ()
void 	g_hash_table_remove_all ()
void 	g_hash_table_steal_all ()

查找

gboolean 	g_hash_table_contains ()
gpointer 	g_hash_table_lookup ()
gboolean 	g_hash_table_lookup_extended ()
gpointer 	g_hash_table_find ()
GList * 	g_hash_table_get_keys ()
GList * 	g_hash_table_get_values ()
gpointer * 	g_hash_table_get_keys_as_array ()

遍历

void 	g_hash_table_foreach ()

测长

guint 	g_hash_table_size ()

引用解引用

GHashTable * 	g_hash_table_ref ()
void 	g_hash_table_unref ()

迭代器

void 	g_hash_table_iter_init ()
gboolean 	g_hash_table_iter_next ()
GHashTable * 	g_hash_table_iter_get_hash_table ()
void 	g_hash_table_iter_replace ()
void 	g_hash_table_iter_remove ()
void 	g_hash_table_iter_steal ()

hash函数

gboolean 	g_direct_equal ()
guint 	g_direct_hash ()
gboolean 	g_int_equal ()
guint 	g_int_hash ()
gboolean 	g_int64_equal ()
guint 	g_int64_hash ()
gboolean 	g_double_equal ()
guint 	g_double_hash ()
gboolean 	g_str_equal ()
guint 	g_str_hash ()

函数功能说明及综合演示

基本功能演示

创建
GHashTable * g_hash_table_new ()
GHashTable * g_hash_table_new_full ()
在创建hash表时传入每个表节点的key及value的释放函数,当hash表被销毁时,对每个节点执行这两个释放函数。
如果有释放函数时,调用remove接口删除一个节点会调到释放函数,这一点后面讲删除一节时会详细讲到。

测长
guint g_hash_table_size ()

销毁
void g_hash_table_destroy ()

插入
gboolean g_hash_table_insert ()
gboolean g_hash_table_add ()
当要插入的key和value相同时,可以使用本函数,不需要再单独传入value

遍历
void g_hash_table_foreach ()

下面演示在不同key和value数据类型情况以上函数的使用方法。
演示程序1:key为int,value为int,key和value值相等
源码见glib_examples\glib_hash\glib_hash_basic_key_int_value_int

#include <glib.h>

#define TEST_ARRAY_LEN 10

static void _test_hash_int_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s: key:%d, value:%d \n", (gchar *)user_data, *(gint *)key, *(gint *)value);
    return;
}

static void test_hash_basic(void)
{
    gint i = 0;
    gint arr[TEST_ARRAY_LEN] = {0};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new(g_int_hash, g_int_equal);

    for(i=0; i<TEST_ARRAY_LEN/2; i++) {
        arr[i] = i;
        g_hash_table_insert(htable, &arr[i], &arr[i]);
    }
    for(i=TEST_ARRAY_LEN/2;i<TEST_ARRAY_LEN;i++) {
        arr[i] = i;
        g_hash_table_add(htable, &arr[i]);
    }

    g_hash_table_foreach(htable, _test_hash_int_foreach_func, "int");

    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic: 
int: key:0, value:0 
int: key:1, value:1 
int: key:3, value:3 
int: key:2, value:2 
int: key:6, value:6 
int: key:7, value:7 
int: key:5, value:5 
int: key:8, value:8 
int: key:4, value:4 
int: key:9, value:9 
htable length: 10 
OK

演示程序2:key为字符串,value也为字符串,key和value值相等
源码见glib_examples\glib_hash\glib_hash_basic_key_str_value_str

#include <glib.h>

#define TEST_ARRAY_LEN 10

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s: key:%s, value:%s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void test_hash_basic(void)
{
    gint i = 0;
    char *arr[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new(g_str_hash, g_str_equal);

    for(i=0; i<TEST_ARRAY_LEN/2; i++) {
        arr[i] = g_strdup_printf("str%d", i);
        g_hash_table_insert(htable, arr[i], arr[i]);
    }
    for(i=TEST_ARRAY_LEN/2;i<TEST_ARRAY_LEN;i++) {
        arr[i] = g_strdup_printf("str%d", i);
        g_hash_table_add(htable, arr[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "str");

    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        g_free(arr[i]);
    }

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic: 
str: key:str9, value:str9 
str: key:str0, value:str0 
str: key:str1, value:str1 
str: key:str2, value:str2 
str: key:str3, value:str3 
str: key:str4, value:str4 
str: key:str5, value:str5 
str: key:str6, value:str6 
str: key:str7, value:str7 
str: key:str8, value:str8 
htable length: 10 
OK

演示程序3:key为int,value为字符串
源码见glib_examples\glib_hash\glib_hash_basic_key_int_value_str

#include <glib.h>

#define TEST_ARRAY_LEN 10

static void _test_hash_mix_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s: key:%d, value:%s \n", (gchar *)user_data, *(gint *)key, (gchar *)value);
    return;
}

static void _test_hash_mix_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_basic(void)
{
    gint i = 0;
    gint iarr[TEST_ARRAY_LEN] = {0};
    gchar *arr[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, _test_hash_mix_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        iarr[i] = i;
        arr[i] = g_strdup_printf("str%d", i);
        g_hash_table_insert(htable, &iarr[i], arr[i]);
    }

    g_hash_table_foreach(htable, _test_hash_mix_foreach_func, "mix");

    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic: 
mix: key:0, value:str0 
mix: key:1, value:str1 
mix: key:3, value:str3 
mix: key:2, value:str2 
mix: key:6, value:str6 
mix: key:7, value:str7 
mix: key:5, value:str5 
mix: key:8, value:str8 
mix: key:4, value:str4 
mix: key:9, value:str9 
htable length: 10 
OK

演示程序4:key为int,value为字符串(错误示例,有段错误)
源码见glib_examples\glib_hash\glib_hash_basic_key_int_value_str_err

#include <glib.h>

#define TEST_ARRAY_LEN 10

static void _test_hash_mix_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s: key:%d, value:%s \n", (gchar *)user_data, GPOINTER_TO_INT(key), (gchar *)value);
    return;
}

static void _test_hash_mix_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_basic(void)
{
    gint i = 0;
    char *arr[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, _test_hash_mix_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        arr[i] = g_strdup_printf("str%d", i);
        g_hash_table_insert(htable, GINT_TO_POINTER(i), arr[i]);
    }

    g_hash_table_foreach(htable, _test_hash_mix_foreach_func, "mix");

    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic:
段错误(吐核)

运行时有段错误,需要进行以下修改。
将上述hash表创建函数传入g_direct_hash和g_direct_equal
即,将
htable = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, _test_hash_mix_value_destroy_func);
改为:
htable = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, _test_hash_mix_value_destroy_func);
再次运行,不会出现段错误。

在创建时指定节点释放函数

示例代码如下:
源码见glib_examples\glib_hash\glib_hash_new_full

#include <glib.h>

#define TEST_ARRAY_LEN 10

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s: key:%s, value:%s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_basic(void)
{
    gint i = 0;
    char *arr[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, _test_hash_str_key_destroy_func, NULL);

    for(i=0; i<TEST_ARRAY_LEN/2; i++) {
        arr[i] = g_strdup_printf("str%d", i);
        g_hash_table_insert(htable, arr[i], arr[i]);
    }
    for(i=TEST_ARRAY_LEN/2;i<TEST_ARRAY_LEN;i++) {
        arr[i] = g_strdup_printf("str%d", i);
        g_hash_table_add(htable, arr[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "str");

    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic: 
str: key:str9, value:str9 
str: key:str0, value:str0 
str: key:str1, value:str1 
str: key:str2, value:str2 
str: key:str3, value:str3 
str: key:str4, value:str4 
str: key:str5, value:str5 
str: key:str6, value:str6 
str: key:str7, value:str7 
str: key:str8, value:str8 
htable length: 10 
OK
替换
gboolean 	g_hash_table_replace ()

替换hash表中的key和value。如果key已经存在,则将原key和value替换掉。如果在创建hash表时指定了key_destroy_func,则替换前本函数会被调用到,如果指定了value_destroy_func,则替换前本函数会被调用到。如果key不存在,则本函数功能相当于g_hash_table_insert。
示例代码如下:
源码见glib_examples\glib_hash\glib_hash_replace

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_print("free key: %s \n", (gchar *)data);
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_print("free value: %s \n", (gchar *)data);
        g_free(data);
    }
}

static void test_hash_basic(void)
{
    gint i = 0;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN-2; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    //key already exist
    key[TEST_ARRAY_LEN-2] = g_strdup_printf("key%d", 1);
    val[TEST_ARRAY_LEN-2] = g_strdup_printf("value%d", 999);
    g_hash_table_replace(htable, key[TEST_ARRAY_LEN-2], val[TEST_ARRAY_LEN-2]);

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "replace-key-exist");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    //key not exist
    key[TEST_ARRAY_LEN-1] = g_strdup_printf("key%d", 888);
    val[TEST_ARRAY_LEN-1] = g_strdup_printf("value%d", 8888);
    g_hash_table_replace(htable, key[TEST_ARRAY_LEN-1], val[TEST_ARRAY_LEN-1]);

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "replace-key-not-exist");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic: 
ori key: key0, value: value0 
ori key: key1, value: value1 
htable length: 2 
free key: key1 
free value: value1 
replace-key-exist key: key0, value: value0 
replace-key-exist key: key1, value: value999 
htable length: 2 
replace-key-not-exist key: key888, value: value8888 
replace-key-not-exist key: key0, value: value0 
replace-key-not-exist key: key1, value: value999 
htable length: 3 
free key: key888 
free value: value8888 
free key: key0 
free value: value0 
free key: key1 
free value: value999 
OK
查找
// 查找key是否在hash表中
gboolean 	g_hash_table_contains ()

// 查找key是否在hash表中,如果存在,则返回value的地址。如果不存在,则返回NULL。
// 本函数无法区分key不存在还是key存在但value为空的情况,如果想区分这两者,可使用g_hash_table_lookup_extended函数。
gpointer 	g_hash_table_lookup ()

// 查找key是否存在hash表中,如果存在,则返回key和value的地址。
// 如果想要删除一个节点,且未设置key和value的释放函数,可以先调用本函数查找到该节点,得到key和value的指针地址,然后自行释放。
gboolean 	g_hash_table_lookup_extended ()

// 自定义查找函数在hash表中查找key或value是否存在,若存在,则返回节点的value。注意本函数查找效率不如g_hash_table_lookup_extended高。
gpointer 	g_hash_table_find ()

// 返回hash表的所有key组成的链表,注意链表的每个节点只是保存了key的指针,内存仍然属于hash表。返回的GList需要调用g_list_free释放(这里释放的是节点,每个节点所指向的值,并没有被释放)。
GList * 	g_hash_table_get_keys ()

// 与g_hash_table_get_keys类似,这里返回的是所有value组成的链表。
GList * 	g_hash_table_get_values ()

// 返回hash表中所有key,但返回的是数组形式。与g_hash_table_get_keys类似,数组只保存了key的指针,内存仍属于hash表。
gpointer * 	g_hash_table_get_keys_as_array ()

查找系列函数示例代码如下:
源码见glib_examples\glib_hash\glib_hash_find

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_contains(void)
{
    gint i = 0;
    gboolean ret = FALSE;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    ret = g_hash_table_contains(htable, key[TEST_ARRAY_LEN/2]);
    g_print("%s %s in hash table \n", key[TEST_ARRAY_LEN/2], ret?"is":"is Not");

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_lookup(void)
{
    gint i = 0;
    char *value = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    value = g_hash_table_lookup(htable, key[1]);
    if(NULL == value) {
        g_print("key[1] value is NULL \n");
    } else {
        g_print("key[1] value is %s \n", value);
    }

    value = g_hash_table_lookup(htable, key[2]);
    if(NULL == value) {
        g_print("key[1] value is NULL \n");
    } else {
        g_print("key[2] value is %s \n", value);
    }

    value = g_hash_table_lookup(htable, "key9");
    if(NULL == value) {
        g_print("key9 value is NULL \n");
    } else {
        g_print("key9 value is %s \n", value);
    }

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_lookup_extended(void)
{
    gint i = 0;
    gboolean ret = FALSE;
    char *ori_key = NULL;
    char *ori_value = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    ret = g_hash_table_lookup_extended(htable, "key1", (gpointer *)&ori_key, (gpointer *)&ori_value);
    if(TRUE == ret) {
        g_print("key1 found, ori_key: %s, value: %s \n", ori_key, ori_value);
    } else {
        g_print("key1 not found \n");
    }

    ret = g_hash_table_lookup_extended(htable, "key9", (gpointer *)&ori_key, (gpointer *)&ori_value);
    if(TRUE == ret) {
        g_print("key9 found, ori_key: %s, value: %s \n", ori_key, ori_value);
    } else {
        g_print("key9 not found \n");
    }

    g_hash_table_destroy(htable);

    return;
}

static gboolean _test_hash_find_ghrfunc
    (gpointer key, gpointer value, gpointer user_data)
{
    if(0 == g_strcmp0((const char *)user_data, (const char *)key)) {
        return TRUE;
    }

    return FALSE;
}

static void test_hash_find(void)
{
    gint i = 0;
    char *value = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    value = g_hash_table_find(htable, _test_hash_find_ghrfunc, "key2");
    if(NULL != value) {
        g_print("key2 found in hash table, value: %s \n", value);
    } else {
        g_print("key2 not found in hash table \n");
    }

    value = g_hash_table_find(htable, _test_hash_find_ghrfunc, "key9");
    if(NULL != value) {
        g_print("key9 found in hash table, value: %s \n", value);
    } else {
        g_print("key9 not found in hash table \n");
    }

    g_hash_table_destroy(htable);

    return;
}

static void _test_hash_list_foreach_func(gpointer data, gpointer user_data)
{
    g_print("list data: %s \n", (gchar *)data);
}

static void test_hash_get_keys(void)
{
    gint i = 0;
    GList *list = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    list = g_hash_table_get_keys(htable);
    g_list_foreach(list, _test_hash_list_foreach_func, NULL);
    g_list_free(list);

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_get_values(void)
{
    gint i = 0;
    GList *list = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    list = g_hash_table_get_values(htable);
    g_list_foreach(list, _test_hash_list_foreach_func, NULL);
    g_list_free(list);

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/contains", test_hash_contains);
    g_test_add_func ("/hash/search/lookup", test_hash_lookup);
    g_test_add_func ("/hash/search/lookup-extended", test_hash_lookup_extended);
    g_test_add_func ("/hash/search/find", test_hash_find);
    g_test_add_func ("/hash/search/get-keys", test_hash_get_keys);
    g_test_add_func ("/hash/search/get-values", test_hash_get_values);

    return g_test_run();
}

运行结果:

/hash/search/contains: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
key2 is in hash table 
OK
/hash/search/lookup: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
key[1] value is NULL 
key[2] value is value2 
key9 value is NULL 
OK
/hash/search/lookup-extended: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
key1 found, ori_key: key1, value: (null) 
key9 not found 
OK
/hash/search/find: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
key2 found in hash table, value: value2 
key9 not found in hash table 
OK
/hash/search/get-keys: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
list data: key2 
list data: key1 
list data: key0 
list data: key3 
OK
/hash/search/get-values: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
list data: value2 
list data: (null) 
list data: value0 
list data: value3 
OK
删除
// 删除一个节点,当hash表创建时使用的是g_hash_table_new_full函数,且已经设置了key或value节点释放函数,如果删除一个节点成功,则会调到释放函数。
// 如果没有设置key或value节点释放函数,则可以先使用g_hash_table_lookup_extended找到该节点,并取出其key和value值,remove方法删除后再对节点进行释放。
gboolean 	g_hash_table_remove ()

// 从hash表删除一个节点,即使设置了key或value节点释放函数,节点被删除时也不会释放,所以节点需要用户自行释放。
// 由于不会调用到key或value节点释放函数,可以先使用g_hash_table_lookup_extended找到该节点,并取出其key和value值,steal方法删除后再对节点进行释放。
gboolean 	g_hash_table_steal ()

// 对每个节点调用一次用户传入的GHRFunc函数,如果GHRFunc返回TRUE,则删除该节点,相应的key或value节点释放函数也会被调到。
guint 	g_hash_table_foreach_remove ()

// 与g_hash_table_foreach_remove类似,但删除节点时,key或value节点释放函数不会被调到。需要用户自行释放删除的节点。
guint 	g_hash_table_foreach_steal ()

// 删除hash表中所有节点,如果已设置key或value节点释放函数,则每对一个节点都会调用这两个释放函数,释放内存。
void 	g_hash_table_remove_all ()

// 与g_hash_table_remove_all类似,但不会调到节点释放函数。需要用户自行释放被删除的节点。
void 	g_hash_table_steal_all ()

删除功能的示例代码如下:
源码见glib_examples\glib_hash\glib_hash_remove

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_print("free key: %s \n", (gchar *)data);
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_print("free value: %s \n", (gchar *)data);
        g_free(data);
    }
}

static void test_hash_remove(void)
{
    gint i = 0;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_remove(htable, key[TEST_ARRAY_LEN/2]);

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "remove");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

static gboolean _test_hash_foreach_remove_ghrfunc
    (gpointer key, gpointer value, gpointer user_data)
{
    if((0 == g_strcmp0("key1", (const char *)key)) 
        || (0 == g_strcmp0("key3", (const char *)key)) ) {
        return TRUE;
    }

    return FALSE;
}

static void test_hash_foreach_remove(void)
{
    gint i = 0;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_foreach_remove(htable, _test_hash_foreach_remove_ghrfunc, NULL);

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "foreach_remove");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_remove_all(void)
{
    gint i = 0;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_remove_all(htable);

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "remove_all");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_steal(void)
{
    gint i = 0;
    gboolean ret = FALSE;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    ret = g_hash_table_steal(htable, key[TEST_ARRAY_LEN/2]);
    if(TRUE == ret) {
        g_print("found key: %s \n", key[TEST_ARRAY_LEN/2]);
        g_free(key[TEST_ARRAY_LEN/2]);
        g_free(val[TEST_ARRAY_LEN/2]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "steal");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

static gboolean _test_hash_foreach_steal_ghrfunc
    (gpointer key, gpointer value, gpointer user_data)
{
    if((0 == g_strcmp0("key1", (const char *)key)) 
        || (0 == g_strcmp0("key3", (const char *)key)) ) {
        return TRUE;
    }

    return FALSE;
}

static void test_hash_foreach_steal(void)
{
    gint i = 0;
    gboolean ret = FALSE;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    ret = g_hash_table_foreach_steal(htable, _test_hash_foreach_steal_ghrfunc, NULL);
    if(2 == ret) {
        g_print("steal key1 and key3 \n");
        g_free(key[1]);
        g_free(val[1]);
        g_free(key[3]);
        g_free(val[3]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "foreach_steal");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_steal_all(void)
{
    gint i = 0;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_steal_all(htable);
    for(i=0; i<TEST_ARRAY_LEN; i++) {
        g_free(key[i]);
        g_free(val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "steal_all");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/remove", test_hash_remove);
    g_test_add_func ("/hash/foreach-remove", test_hash_foreach_remove);
    g_test_add_func ("/hash/remove-all", test_hash_remove_all);
    g_test_add_func ("/hash/steal", test_hash_steal);
    g_test_add_func ("/hash/foreach-steal", test_hash_foreach_steal);
    g_test_add_func ("/hash/steal-all", test_hash_steal_all);

    return g_test_run();
}

运行结果:

/hash/remove: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
free key: key2 
free value: value2 
remove key: key3, value: value3 
remove key: key0, value: value0 
remove key: key1, value: value1 
htable length: 3 
free key: key3 
free value: value3 
free key: key0 
free value: value0 
free key: key1 
free value: value1 
OK
/hash/foreach-remove: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
free key: key3 
free value: value3 
free key: key1 
free value: value1 
foreach_remove key: key0, value: value0 
foreach_remove key: key2, value: value2 
htable length: 2 
free key: key0 
free value: value0 
free key: key2 
free value: value2 
OK
/hash/remove-all: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
free key: key3 
free value: value3 
free key: key0 
free value: value0 
free key: key1 
free value: value1 
free key: key2 
free value: value2 
htable length: 0 
OK
/hash/steal: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
found key: key2 
steal key: key3, value: value3 
steal key: key0, value: value0 
steal key: key1, value: value1 
htable length: 3 
free key: key3 
free value: value3 
free key: key0 
free value: value0 
free key: key1 
free value: value1 
OK
/hash/foreach-steal: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
steal key1 and key3 
foreach_steal key: key0, value: value0 
foreach_steal key: key2, value: value2 
htable length: 2 
free key: key0 
free value: value0 
free key: key2 
free value: value2 
OK
/hash/steal-all: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
htable length: 0 
OK
迭代器

迭代器相关函数如下:

void 	g_hash_table_iter_init ()
gboolean 	g_hash_table_iter_next ()
GHashTable * 	g_hash_table_iter_get_hash_table ()
void 	g_hash_table_iter_replace ()
void 	g_hash_table_iter_remove ()
void 	g_hash_table_iter_steal ()

下面举例说明。
源码见glib_examples\glib_hash\glib_hash_iter

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_iterator(void)
{
    gint i = 0;
    GHashTableIter iter;
    gpointer iter_key = NULL;
    gpointer iter_val = NULL;
    gpointer k = NULL;
    gpointer v = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_iter_init(&iter, htable);
    while(g_hash_table_iter_next(&iter, &iter_key, &iter_val)) {
        g_print("iter. key:%s value:%s \n", (char *)iter_key, (char *)iter_val);
        if(0 == g_strcmp0((char *)iter_key, "key1")) {
            g_hash_table_iter_replace(&iter, g_strdup_printf("replace-value"));
        }else if(0 == g_strcmp0((char *)iter_key, "key2")) {
            g_hash_table_iter_remove(&iter);
        } else if(0 == g_strcmp0((char *)iter_key, "key0")) {
            g_hash_table_iter_steal(&iter);
            g_free(iter_key);
            g_free(iter_val);
        } else {
            //Nothing to do
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "iter-replace");

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/iterator", test_hash_iterator);

    return g_test_run();
}

运行结果:

/hash/iterator: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
iter. key:key3 value:value3 
iter. key:key0 value:value0 
iter. key:key1 value:value1 
iter. key:key2 value:value2 
iter-replace key: key3, value: value3 
iter-replace key: key1, value: replace-value 
OK

把while循环内的代码修改一下,再次运行。
源码见glib_examples\glib_hash\glib_hash_iter_mem_leak_err

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_iterator(void)
{
    gint i = 0;
    GHashTableIter iter;
    gpointer iter_key = NULL;
    gpointer iter_val = NULL;
    gpointer k = NULL;
    gpointer v = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_iter_init(&iter, htable);
    while(g_hash_table_iter_next(&iter, &iter_key, &iter_val)) {
        g_print("iter. key:%s value:%s \n", (char *)iter_key, (char *)iter_val);
        if(0 == g_strcmp0((char *)iter_key, "key1")) {
            g_hash_table_iter_replace(&iter, g_strdup_printf("replace-value"));
        }
        if(0 == g_strcmp0((char *)iter_key, "key2")) {
            g_hash_table_iter_remove(&iter);
        }
        if(0 == g_strcmp0((char *)iter_key, "key0")) {
            g_hash_table_iter_steal(&iter);
            g_free(iter_key);
            g_free(iter_val);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "iter-replace");

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/iterator", test_hash_iterator);

    return g_test_run();
}

运行结果:

/hash/iterator: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
iter. key:key3 value:value3 
iter. key:key0 value:value0 
iter. key:key1 value:value1 
iter. key:key2 value:value2 
iter-replace key: key3, value: value3 
iter-replace key: key1, value: replace-value 
OK

看上去仍得到了预期的结果,但使用valgrind检查,发现有内存问题。

[root@centos7_6 build]# valgrind --tool=memcheck --leak-check=full ./glib_hash_iter_mem_leak_err
==51907== Memcheck, a memory error detector
==51907== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==51907== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==51907== Command: ./glib_hash_iter_mem_leak_err
==51907== 
/hash/iterator: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
htable length: 4 
iter. key:key3 value:value3 
iter. key:key0 value:value0 
iter. key:key1 value:value1 
iter. key:key2 value:value2 
==51907== Invalid read of size 1
==51907==    at 0x4C2F1B1: strcmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==51907==    by 0x401058: test_hash_iterator (in /root/glib_examples/glib_hash/glib_hash_iter_mem_leak_err/build/glib_hash_iter_mem_leak_err)
==51907==    by 0x4EA3779: test_case_run (gtestutils.c:2158)
==51907==    by 0x4EA3779: g_test_run_suite_internal (gtestutils.c:2241)
==51907==    by 0x4EA392D: g_test_run_suite_internal (gtestutils.c:2253)
==51907==    by 0x4EA3B3D: g_test_run_suite (gtestutils.c:2328)
==51907==    by 0x4EA3B60: g_test_run (gtestutils.c:1596)
==51907==    by 0x401110: main (in /root/glib_examples/glib_hash/glib_hash_iter_mem_leak_err/build/glib_hash_iter_mem_leak_err)
==51907==  Address 0x576e330 is 0 bytes inside a block of size 5 free'd
==51907==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==51907==    by 0x400E10: _test_hash_str_key_destroy_func (in /root/glib_examples/glib_hash/glib_hash_iter_mem_leak_err/build/glib_hash_iter_mem_leak_err)
==51907==    by 0x4E6EB4F: g_hash_table_remove_node (ghash.c:455)
==51907==    by 0x4E6EBCB: iter_remove_or_steal (ghash.c:845)
==51907==    by 0x401044: test_hash_iterator (in /root/glib_examples/glib_hash/glib_hash_iter_mem_leak_err/build/glib_hash_iter_mem_leak_err)
==51907==    by 0x4EA3779: test_case_run (gtestutils.c:2158)
==51907==    by 0x4EA3779: g_test_run_suite_internal (gtestutils.c:2241)
==51907==    by 0x4EA392D: g_test_run_suite_internal (gtestutils.c:2253)
==51907==    by 0x4EA3B3D: g_test_run_suite (gtestutils.c:2328)
==51907==    by 0x4EA3B60: g_test_run (gtestutils.c:1596)
==51907==    by 0x401110: main (in /root/glib_examples/glib_hash/glib_hash_iter_mem_leak_err/build/glib_hash_iter_mem_leak_err)
......(以下省略)

根据valgrind输出信息,可以猜测,strcmp访问了已经释放过的内存。
实际上该问题出在以下两行:

        if(0 == g_strcmp0((char *)iter_key, "key1")) {
            g_hash_table_iter_replace(&iter, g_strdup_printf("replace-value"));
        }
        if(0 == g_strcmp0((char *)iter_key, "key2")) {
            g_hash_table_iter_remove(&iter);
        }

g_hash_table_iter_replace调用之后,iter_key和iter_key都会被释放,后面就不能再次访问iter_key这段内存了。如果访问该段内存,相当于使用了野指针。

Hash函数
gboolean 	g_direct_equal ()
guint 	g_direct_hash ()
gboolean 	g_int_equal ()
guint 	g_int_hash ()
gboolean 	g_int64_equal ()
guint 	g_int64_hash ()
gboolean 	g_double_equal ()
guint 	g_double_hash ()
gboolean 	g_str_equal ()
guint 	g_str_hash ()

上述hash函数的类型是指key的数据类型,value的值可以随意。
除了以上几种key类型,GLib还支持以下类型的key。
GString类型的key:

g_string_equal 
g_string_hash 

GBytes类型的key:

g_bytes_equal
g_bytes_hash 

GVariant类型的key:

g_variant_equal 
g_variant_hash 

专题

Hash表数据存储方式

GHashTable是一个不透明数据结构,无法像链表队列那样查看其内部结构,但仍可以使用分析链表节点内存的方式分析GHashTable节点的内存分布情况。
在下面的例子中,首先将字符串型hash插入不同的key和value,遍历一遍,然后将传入的key和value值修改,再遍历,即可得知GHashTable在插入节点时是自己创建了内存空间还是使用外部的内存空间。

源码见glib_examples\glib_hash\glib_hash_mem

#include <glib.h>

#define TEST_ARRAY_LEN 10

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void test_hash_basic(void)
{
    gint i = 0;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i][0] = 'K';
        val[i][0] = 'V';
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "change");

    g_print("htable length: %d \n", g_hash_table_size(htable));

    g_hash_table_destroy(htable);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        g_free(key[i]);
        g_free(val[i]);
    }

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/basic", test_hash_basic);

    return g_test_run();
}

运行结果:

/hash/basic: 
ori key: key0, value: value0 
ori key: key1, value: value1 
ori key: key2, value: value2 
ori key: key3, value: value3 
ori key: key4, value: value4 
ori key: key5, value: value5 
ori key: key6, value: value6 
ori key: key7, value: value7 
ori key: key8, value: value8 
ori key: key9, value: value9 
change key: Key0, value: Value0 
change key: Key1, value: Value1 
change key: Key2, value: Value2 
change key: Key3, value: Value3 
change key: Key4, value: Value4 
change key: Key5, value: Value5 
change key: Key6, value: Value6 
change key: Key7, value: Value7 
change key: Key8, value: Value8 
change key: Key9, value: Value9 
htable length: 10 
OK

结果改变,说明Hash表创建时,只会将内部的key和value的指针指向传入的参数,不会真正拷贝内存。因为使用的是外部的内存空间,需要特别注意在Hash表使用过程中传入变量的生命周期,这些变量的内存不可随便释放。

将hash表键值保存到字符串数组
// 获取hash表中的所有key,并将其放到一个字符串数组中。
// 第二个参数length的作用是返回实际的key个数,因为key的值有可能为空,如果key为空,没有length这个参数就无法得知数组的真正长度。
gpointer * 	g_hash_table_get_keys_as_array ()

先来看一个错误示例(运行时会有段错误):
源码见glib_examples\glib_hash\glib_hash_key_to_array_err

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_get_keys_as_array(void)
{
    gint i = 0;
    guint length = 0;
    gchar **strv = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    strv = (gchar **)g_hash_table_get_keys_as_array(htable, &length);
    for(i=0;i<length;i++) {
        g_print("strv[%d]: %s \n", i, strv[i]);
    }
    g_strfreev(strv);

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/get-keys-as-array", test_hash_get_keys_as_array);

    return g_test_run();
}

运行结果:

/hash/search/get-keys-as-array: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
strv[0]: key3 
strv[1]: key0 
strv[2]: key1 
strv[3]: key2 
段错误 (核心已转储)

使用valgrind运行一下。

[root@centos7_6 build]# valgrind --tool=memcheck --leak-check=full ./glib_hash_key_to_array_err
==49979== Memcheck, a memory error detector
==49979== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==49979== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==49979== Command: ./glib_hash_key_to_array_err
==49979== 
/hash/search/get-keys-as-array: 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
strv[0]: key3 
strv[1]: key0 
strv[2]: key1 
strv[3]: key2 
==49979== Invalid free() / delete / delete[] / realloc()
==49979==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==49979==    by 0x400CB0: _test_hash_str_key_destroy_func (in /root/glib_examples/glib_hash/glib_hash_key_to_array_err/build/glib_hash_key_to_array_err)
==49979==    by 0x4E6EFA3: g_hash_table_remove_all_nodes.part.0 (ghash.c:545)
==49979==    by 0x4E6FDBA: g_hash_table_remove_all_nodes (ghash.c:1426)
==49979==    by 0x4E6FDBA: g_hash_table_remove_all (ghash.c:1429)
==49979==    by 0x4E6FDFD: g_hash_table_destroy (ghash.c:1122)
==49979==    by 0x400EC0: test_hash_get_keys_as_array (in /root/glib_examples/glib_hash/glib_hash_key_to_array_err/build/glib_hash_key_to_array_err)
==49979==    by 0x4EA3779: test_case_run (gtestutils.c:2158)
==49979==    by 0x4EA3779: g_test_run_suite_internal (gtestutils.c:2241)
==49979==    by 0x4EA392D: g_test_run_suite_internal (gtestutils.c:2253)
==49979==    by 0x4EA392D: g_test_run_suite_internal (gtestutils.c:2253)
==49979==    by 0x4EA3B3D: g_test_run_suite (gtestutils.c:2328)
==49979==    by 0x4EA3B60: g_test_run (gtestutils.c:1596)
==49979==    by 0x400F03: main (in /root/glib_examples/glib_hash/glib_hash_key_to_array_err/build/glib_hash_key_to_array_err)
==49979==  Address 0x576f120 is 0 bytes inside a block of size 5 free'd
==49979==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==49979==    by 0x4E9E098: g_strfreev (gstrfuncs.c:2487)
==49979==    by 0x400EB4: test_hash_get_keys_as_array (in /root/glib_examples/glib_hash/glib_hash_key_to_array_err/build/glib_hash_key_to_array_err)
==49979==    by 0x4EA3779: test_case_run (gtestutils.c:2158)
==49979==    by 0x4EA3779: g_test_run_suite_internal (gtestutils.c:2241)
==49979==    by 0x4EA392D: g_test_run_suite_internal (gtestutils.c:2253)
==49979==    by 0x4EA392D: g_test_run_suite_internal (gtestutils.c:2253)
==49979==    by 0x4EA3B3D: g_test_run_suite (gtestutils.c:2328)
==49979==    by 0x4EA3B60: g_test_run (gtestutils.c:1596)
==49979==    by 0x400F03: main (in /root/glib_examples/glib_hash/glib_hash_key_to_array_err/build/glib_hash_key_to_array_err)
==49979== 
......(以下省略)

可以看出是在g_strfreev和_test_hash_str_key_destroy_func两处出错,Invalid free(),因此有理由怀疑是对同一内存进行了多次释放。下面这两个地址打印出来,看是否相同。

示例代码如下:
源码见glib_examples\glib_hash\glib_hash_key_to_array_addr_err

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_get_keys_as_array(void)
{
    gint i = 0;
    guint length = 0;
    gchar **strv = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_print("key[%d](addr:%p): %s \n", i, key[i], key[i]);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    strv = (gchar **)g_hash_table_get_keys_as_array(htable, &length);
    for(i=0;i<length;i++) {
        g_print("strv[%d](addr:%p): %s \n", i, strv[i], strv[i]);
    }
    g_strfreev(strv);

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/get-keys-as-array", test_hash_get_keys_as_array);

    return g_test_run();
}

运行结果:

/hash/search/get-keys-as-array: 
key[0](addr:0x2210f70): key0 
key[1](addr:0x22120a0): key1 
key[2](addr:0x22120c0): key2 
key[3](addr:0x22121f0): key3 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
strv[0](addr:0x22121f0): key3 
strv[1](addr:0x2210f70): key0 
strv[2](addr:0x22120a0): key1 
strv[3](addr:0x22120c0): key2 
段错误 (核心已转储)

与猜测一致,g_hash_table_get_keys_as_array并不会将key的值重新复制一份,其内容只是指向各个key的指针,内存还在hash表中。
对于上述程序段错误,有至少以下三种方法可以修复。
方法一:在g_hash_table_new_full时不指定key的释放函数,得到key的数组后使用g_strfreev释放。
示例代码如下:
源码见glib_examples\glib_hash\glib_hash_key_to_array1

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_get_keys_as_array(void)
{
    gint i = 0;
    guint length = 0;
    gchar **strv = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        NULL, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_print("key[%d](addr:%p): %s \n", i, key[i], key[i]);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    strv = (gchar **)g_hash_table_get_keys_as_array(htable, &length);
    for(i=0;i<length;i++) {
        g_print("strv[%d](addr:%p): %s \n", i, strv[i], strv[i]);
    }
    g_strfreev(strv);

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/get-keys-as-array", test_hash_get_keys_as_array);

    return g_test_run();
}

运行结果:

/hash/search/get-keys-as-array: 
key[0](addr:0xe3ff70): key0 
key[1](addr:0xe410a0): key1 
key[2](addr:0xe410c0): key2 
key[3](addr:0xe411f0): key3 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
strv[0](addr:0xe411f0): key3 
strv[1](addr:0xe3ff70): key0 
strv[2](addr:0xe410a0): key1 
strv[3](addr:0xe410c0): key2 
OK

方法二:在g_hash_table_new_full时仍然指定key的释放函数,不使用g_strfreev释放key的数组,直接释放一级指针。
示例代码如下:
源码见glib_examples\glib_hash\glib_hash_key_to_array2

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_get_keys_as_array(void)
{
    gint i = 0;
    guint length = 0;
    gchar **strv = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_print("key[%d](addr:%p): %s \n", i, key[i], key[i]);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    strv = (gchar **)g_hash_table_get_keys_as_array(htable, &length);
    for(i=0;i<length;i++) {
        g_print("strv[%d](addr:%p): %s \n", i, strv[i], strv[i]);
    }
    g_free(strv);

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/get-keys-as-array", test_hash_get_keys_as_array);

    return g_test_run();
}

运行结果:

/hash/search/get-keys-as-array: 
key[0](addr:0x15a8f70): key0 
key[1](addr:0x15aa0a0): key1 
key[2](addr:0x15aa0c0): key2 
key[3](addr:0x15aa1f0): key3 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
strv[0](addr:0x15aa1f0): key3 
strv[1](addr:0x15a8f70): key0 
strv[2](addr:0x15aa0a0): key1 
strv[3](addr:0x15aa0c0): key2 
OK

方法三:在节点destroy前,先调用g_hash_table_steal_all,将所有的节点从hash表移出。将得到的key数组使用g_strfreev释放,value分别使用g_free释放。
示例代码如下:
源码见glib_examples\glib_hash\glib_hash_key_to_array3

#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_get_keys_as_array(void)
{
    gint i = 0;
    guint length = 0;
    gchar **strv = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_print("key[%d](addr:%p): %s \n", i, key[i], key[i]);
        if(1 == i) {
            g_free(val[i]);
            val[i] = NULL;
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    strv = (gchar **)g_hash_table_get_keys_as_array(htable, &length);
    for(i=0;i<length;i++) {
        g_print("strv[%d](addr:%p): %s \n", i, strv[i], strv[i]);
    }

    g_hash_table_steal_all(htable);
    
    g_strfreev(strv);
    for(i=0;i<TEST_ARRAY_LEN;i++) {
        if(NULL != val[i]) {
            g_free(val[i]);
        }
    }

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/get-keys-as-array", test_hash_get_keys_as_array);

    return g_test_run();
}

运行结果:

/hash/search/get-keys-as-array: 
key[0](addr:0x1758f70): key0 
key[1](addr:0x175a0a0): key1 
key[2](addr:0x175a0c0): key2 
key[3](addr:0x175a1f0): key3 
ori key: key3, value: value3 
ori key: key0, value: value0 
ori key: key1, value: (null) 
ori key: key2, value: value2 
htable length: 4 
strv[0](addr:0x175a1f0): key3 
strv[1](addr:0x1758f70): key0 
strv[2](addr:0x175a0a0): key1 
strv[3](addr:0x175a0c0): key2 
OK
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值