原文地址: http://hi.baidu.com/study_together/blog/item/7db6da1d7acfbbf91ad5763e.html
编译:gcc -g -Wall -O0 fuck.c -o fuck `pkg-config --libs --cflags glib-2.0`
1
一些简单的散列表操作 有错误需要调试
这里是一些示例,可以生动地展示以上的理论:
#include <glib.h>
#include <stdio.h>
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(hash, "Virginia", "Richmond");
g_hash_table_insert(hash, "Texas", "Austin");
g_hash_table_insert(hash, "Ohio", "Columbus");
printf("There are %d keys in the hash\n", g_hash_table_size(hash));
printf("The capital of Texas is %s\n", g_hash_table_lookup(hash, "Texas"));
gboolean found = g_hash_table_remove(hash, "Virginia");
printf("The value 'Virginia' was %sfound and removed\n", found ? "" : "not ");
g_hash_table_destroy(hash);
return 0;
}***** Output *****
There are 3 keys in the hash
The capital of Texas is Austin
The value 'Virginia' was found and removed
2
插入和替换值
当使用 g_hash_table_insert 插入键时,GHashTable 首先检查那个键是否已经存在。如果已经存在,那么那个值会被替换,
而键不会被替换。如果希望同时替换键和值,那么需要使用 g_hash_table_replace。它稍有不同,因此在下面同时展示了二者:
#include <glib.h>
#include <stdio.h>
static char* texas_1, *texas_2;
void key_destroyed(gpointer data) {
printf("Got a key destroy call for %s\n", data == texas_1 ? "texas_1" : "texas_2");
}
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new_full(g_str_hash, g_str_equal,
(GDestroyNotify)key_destroyed, NULL);
texas_1 = g_strdup("Texas");
texas_2 = g_strdup("Texas");
g_hash_table_insert(hash, texas_1, "Austin");
printf("Calling insert with the texas_2 key\n");
g_hash_table_insert(hash, texas_2, "Houston");
printf("Calling replace with the texas_2 key\n");
g_hash_table_replace(hash, texas_2, "Houston");
printf("Destroying hash, so goodbye texas_2\n");
g_hash_table_destroy(hash);
g_free(texas_1);
g_free(texas_2);
return 0;
}***** Output *****
Calling insert with the texas_2 key
Got a key destroy call for texas_2
Calling replace with the texas_2 key
Got a key destroy call for texas_1
Destroying hash, so goodbye texas_2
Got a key destroy call for texas_2
3
遍历 键/值 对
有时需要遍历所有的 键/值 对。这里是如何使用 g_hash_table_foreach 来完成那项任务:
#include <glib.h>
#include <stdio.h>
void iterator(gpointer key, gpointer value, gpointer user_data) {
printf(user_data, *(gint*)key, value);
}
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new(g_int_hash, g_int_equal);
gint* k_one = g_new(gint, 1), *k_two = g_new(gint, 1), *k_three = g_new(gint, 1);
*k_one = 1, *k_two=2, *k_three = 3;
g_hash_table_insert(hash, k_one, "one");
g_hash_table_insert(hash, k_two, "four");
g_hash_table_insert(hash, k_three, "nine");
g_hash_table_foreach(hash, (GHFunc)iterator, "The square of %d is %s\n");
g_hash_table_destroy(hash);
return 0;
}***** Output *****
The square of 1 is one
The square of 2 is four
The square of 3 is nine
查找条目
使用 g_hash_table_find 函数来查找某个特定的值。这个函数支持查看每一个 键/值 对,直到定位到期望的值。这里是一个示例:
#include <glib.h>
#include <stdio.h>
void value_destroyed(gpointer data) {
printf("Got a value destroy call for %d\n", GPOINTER_TO_INT(data));
}
gboolean finder(gpointer key, gpointer value, gpointer user_data) {
return (GPOINTER_TO_INT(key) + GPOINTER_TO_INT(value)) == 42;
}
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL,
(GDestroyNotify)value_destroyed);
g_hash_table_insert(hash, GINT_TO_POINTER(6), GINT_TO_POINTER(36));
g_hash_table_insert(hash, GINT_TO_POINTER(10), GINT_TO_POINTER(12));
g_hash_table_insert(hash, GINT_TO_POINTER(20), GINT_TO_POINTER(22));
gpointer item_ptr = g_hash_table_find(hash, (GHRFunc)finder, NULL);
gint item = GPOINTER_TO_INT(item_ptr);
printf("%d + %d == 42\n", item, 42-item);
g_hash_table_destroy(hash);
return 0;
}***** Output *****
36 + 6 == 42
Got a value destroy call for 36
Got a value destroy call for 22
Got a value destroy call for 12
5
难处理的情形:从表中删除
偶尔可能需要从一个 GHashTable 中删除某个条目,但却没有获得 GHashTable 所提供的任意 GDestroyNotify 函数的回调。
要完成此任务,或者可以根据具体的键使用 g_hash_table_steal,或者根据所有匹配某个条件的键使用 g_hash_table_foreach_steal。
#include <glib.h>
#include <stdio.h>
gboolean wide_open(gpointer key, gpointer value, gpointer user_data) {
return TRUE;
}
void key_destroyed(gpointer data) {
printf("Got a GDestroyNotify callback\n");
}
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new_full(g_str_hash, g_str_equal,
(GDestroyNotify)key_destroyed,
(GDestroyNotify)key_destroyed);
g_hash_table_insert(hash, "Texas", "Austin");
g_hash_table_insert(hash, "Virginia", "Richmond");
g_hash_table_insert(hash, "Ohio", "Columbus");
g_hash_table_insert(hash, "Oregon", "Salem");
g_hash_table_insert(hash, "New York", "Albany");
printf("Removing New York, you should see two callbacks\n");
g_hash_table_remove(hash, "New York");
if (g_hash_table_steal(hash, "Texas")) {
printf("Texas has been stolen, %d items remaining\n", g_hash_table_size(hash));
}
printf("Stealing remaining items\n");
g_hash_table_foreach_steal(hash, (GHRFunc)wide_open, NULL);
printf("Destroying the GHashTable, but it's empty, so no callbacks\n");
g_hash_table_destroy(hash);
return 0;
}***** Output *****
Removing New York, you should see two callbacks
Got a GDestroyNotify callback
Got a GDestroyNotify callback
Texas has been stolen, 3 items remaining
Stealing remaining items
Destroying the GHashTable, but it's empty, so no callbacks
6
高级查找:找到键和值
针对需要从表中同时获得键和值的情况,GHashTable 提供了一个 g_hash_table_lookup_extended 函数。
它与 g_hash_table_lookup 非常类似,但要接受更多两个参数。这些都是“out”参数;也就是说,它们是双重间接指针,当数据被定位时将指向它
。这里是它的工作方式:
#include <glib.h>
#include <stdio.h>
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(hash, "Texas", "Austin");
g_hash_table_insert(hash, "Virginia", "Richmond");
g_hash_table_insert(hash, "Ohio", "Columbus");
char* state = NULL;
char* capital = NULL;
char** key_ptr = &state;
char** value_ptr = &capital;
gboolean result = g_hash_table_lookup_extended(hash, "Ohio", (gpointer*)key_ptr, (gpointer*)value_ptr);
if (result) {
printf("Found that the capital of %s is %s\n", capital, state);
}
if (!g_hash_table_lookup_extended(hash, "Vermont", (gpointer*)key_ptr, (gpointer*)value_ptr)) {
printf("Couldn't find Vermont in the hash table\n");
}
g_hash_table_destroy(hash);
return 0;
}***** Output *****
Found that the capital of Columbus is Ohio
Couldn't find Vermont in the hash table
7
每个键多个值 有错误需要调试
到目前为止已经介绍了每个键只拥有一个值的散列。不过有时您需要让一个键持有多个值。当出现这种需求时,
使用 GSList 作为值并及 GSList 添加新的值通常是一个好的解决方案。不过,这需要稍多一些工作,如本例中所示:
#include <glib.h>
#include <stdio.h>
void print(gpointer key, gpointer value, gpointer data) {
printf("Here are some cities in %s: ", key);
g_slist_foreach((GSList*)value, (GFunc)printf, NULL);
printf("\n");
}
void destroy(gpointer key, gpointer value, gpointer data) {
printf("Freeing a GSList, first item is %s\n", ((GSList*)value)->data);
g_slist_free(value);
}
int main(int argc, char** argv) {
GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(hash, "Texas",
g_slist_append(g_hash_table_lookup(hash, "Texas"), "Austin "));
g_hash_table_insert(hash, "Texas",
g_slist_append(g_hash_table_lookup(hash, "Texas"), "Houston "));
g_hash_table_insert(hash, "Virginia",
g_slist_append(g_hash_table_lookup(hash, "Virginia"), "Richmond "));
g_hash_table_insert(hash, "Virginia",
g_slist_append(g_hash_table_lookup(hash, "Virginia"), "Keysville "));
g_hash_table_foreach(hash, print, NULL);
g_hash_table_foreach(hash, destroy, NULL);
g_hash_table_destroy(hash);
return 0;
}***** Output *****
Here are some cities in Texas: Austin Houston
Here are some cities in Virginia: Richmond Keysville
Freeing a GSList, first item is Austin
Freeing a GSList, first item is Richmond
完