Cannot look up existing key using g_hash_table_lookup

The problem I try to solve is as follow. Given this input: [1-3, 1-2, 3-1, 1-1, 1-2], I want to build a hashtable that use the first value of a pair as the key, the second value of a pair as the value, particularly the min and the max only. So the expect output will be:

1 ā†’ [1, 3]
3 ā†’ [1, 1]

I think of using GHashTable, but I cannot look up the key I inserted previously, g_hash_table_lookup always returns NULL. My current code:

#define VALUE_SIZE 2
#define MIN_INDEX 0
#define MAX_INDEX 1

GHashTable* foo(uint8_t* firsts, uint8_t* seconds, uint32_t size)
{
    GHashTable* ht = g_hash_table_new_full(
            (GHashFunc)g_direct_hash,
            (GEqualFunc)g_direct_equal,
            (GDestroyNotify)g_free,
            (GDestroyNotify)g_free);

    for(int i = 0; i < size; i++)
    {
        uint8_t* value = (uint8_t*)g_hash_table_lookup(ht, firsts + i); // I also try &firsts[i] but still not work
        if(value)
        {
            if(value[MIN_INDEX] > seconds[i] || value[MAX_INDEX] < seconds[i])
            {
                uint8_t* key = (uint8_t *)g_malloc0(sizeof(uint8_t));
                uint8_t* new_value = (uint8_t *)g_malloc0(sizeof(uint8_t) * VALUE_SIZE);

                *key = firsts[i];
                new_value[MIN_INDEX] = seconds[i] < value[MIN_INDEX] ? seconds[i] : value[MIN_INDEX];
                new_value[MAX_INDEX] = seconds[i] > value[MAX_INDEX] ? seconds[i] : value[MAX_INDEX];

                g_hash_table_insert(ht, key, new_value);

                g_message("old key updated: %d -> [%d, %d]", *key, new_value[MIN_INDEX], new_value[MAX_INDEX]);
            }
        }
        else
        {
            uint8_t* key = (uint8_t *)g_malloc0(sizeof(uint8_t));
            uint8_t* value = (uint8_t *)g_malloc0(sizeof(uint8_t) * VALUE_SIZE);

            *key = firsts[i];
            value[MIN_INDEX] = seconds[i];
            value[MAX_INDEX] = seconds[i];

            g_hash_table_insert(ht, key, value);

            g_message("new key added: %d -> [%d, %d]", *key, value[MIN_INDEX], value[MAX_INDEX]);
        }
    }

    return ht;
}

Output:

** Message: 18:08:30.780: new key added: 1 -> [3, 3]
** Message: 18:08:30.780: new key added: 1 -> [2, 2]
** Message: 18:08:30.780: new key added: 3 -> [1, 1]
** Message: 18:08:30.780: new key added: 1 -> [1, 1]
** Message: 18:08:30.780: new key added: 1 -> [2, 2]

Instead of updating the value for key 1, I keeping adding it as a new key. What did I do wrong?

You are using the pointers to the newly allocated key as keys. Those will not match pointers to memory allocated elsewhere. What you want to use instead of allocating new memory is GINT_TO_POINTER to cast firsts[i] to look like a pointer.

1 Like

Thank you for suggestion, the reason why I allocated new memory is the because the inputs are not guaranteed to exists during the lifetime of the hashtable Iā€™m creating. If I understand the method you suggested correctly, I can just create a fake pointer from the actual value pointed to by the input pointer, and not freeing this fake pointer. So:

GHashTable* ht = g_hash_table_new_full(
            (GHashFunc)g_direct_hash,
            (GEqualFunc)g_direct_equal,
            (GDestroyNotify)NULL,
            (GDestroyNotify)g_free);

uint8_t* key = GUINT_TO_POINTER(firsts[i]);

Is that correct?

That looks correct, but I would use void* or gpointer instead of uint8_t*.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.