Given the code snippet:
#include <glib.h>
#include <stdio.h>
void print_city(gpointer value, gpointer data)
{
printf("%s, ", value);
}
void print(gpointer key, gpointer value, gpointer data)
{
printf("Here are some cities in %s: ", key);
g_slist_foreach((GSList *)value, (GFunc)print_city, 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,
"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_insert(hash,
"Texas",
g_slist_append(g_hash_table_lookup(hash, "Texas"), "Houston")
);
g_hash_table_insert(hash,
"Texas",
g_slist_append(g_hash_table_lookup(hash, "Texas"), "Austin")
);
g_hash_table_foreach(hash, print, NULL);
g_hash_table_foreach(hash, destroy, NULL);
g_hash_table_destroy(hash);
return 0;
}
We can notice that the lines in main
function that calls g_hash_table_insert
, looks a bit convoluted, repeating itself, hence I was looking code alternatives to simplify the value parameter. With that in mind, my first attempt to change the code is the following (comments added)
GSList *list = NULL;
// Adding the first element to `list`
// list contains the pointer to the GSList head
list = g_slist_append(list, "Austin");
// Inserting the list (an address to a GSLIST) into
// the value of "Texas" key.
g_hash_table_insert(hash, "Texas", list);
// Retrieves the content of "Texas" key.
// (That is right now the pointer to the GSList head)
// and stores into value pointer
list = g_hash_table_lookup(hash, "Texas");
// Add the string "Houston" to the GSList and stores
// the new head at `value` to keep track of head.
list = g_slist_append(list, "Houston");
// Updates the 'key' Texas with list.
g_hash_table_insert(hash, "Texas", list);
Does not looks much better. I have also added a few comments in code to describe my understanding.
Question 1: Does my understanding (expressed in comments) are correct?
Question 2: Keeping the code consistency, is there any way to improve the code above?
I noticed that I could remove all calls to g_hash_table_insert
after the first one, maybe sacrificing some consistency. The code in this case would looks like this
GSList *list = NULL;
list = g_slist_append(list, "Austin");
g_hash_table_insert(hash, "Texas", list);
list = g_hash_table_lookup(hash, "Texas");
list = g_slist_append(list, "Houston");
Question 3: How this change affects the consistency?
Question 4: Which behaviors could emerge from this change?
Anyhow, given this previous snippet I tried to make things more “organized” hence I reached the follow snippet to update the list in GHashTable:
GSList *list = NULL;
g_hash_table_insert(hash, "Texas", list);
list = g_hash_table_lookup(hash, "Texas");
list = g_slist_append(list, "Austin");
list = g_slist_append(list, "Houston");
The code above seems more organized, but fails completely in work (even triggering segfault on free
calls). I could not understand why this last snippet fails.
Question 5: Why the segfault is happening?
Question 6: Is there a less convoluted way to handle GSLists
in GHashTables
that not uses the initial construction?