Ошибка поиска в хеш-таблице GLib

Я пытаюсь научиться использовать контейнер GHashTable из glib и наблюдаю странное поведение при поиске. Проблема сводится к следующему:

#include <glib.h>
#include <stdio.h>

GHashTable *h;
char val[]  = {'H', 'E', 'L', 'L', 'O',0};

void f1()
{
   int k;
   scanf("%d", &k);
        g_hash_table_insert(h, &k, val);
}

void f2()
{
   int m;
   f1();
   scanf("%d", &m);
   gpointer *p = g_hash_table_lookup(h, &m);
   printf("%s\n", (const char*)p);
}

int main()
{
   h = g_hash_table_new(g_int_hash, g_int_equal);
   f2();
   return 0;
}

В функции f2 результатом g_hash_table_lookup является 0x00. Однако, если я вызову f1 из main перед вызовом f2 и пропущу вызов f1 из f2, код будет работать, как и ожидалось, и выведет «HELLO».

Я думаю, что мне не хватает чего-то очень простого здесь. Как правильно выполнять вставки и поиск хэш-таблицы в glib?


person Community    schedule 01.06.2013    source источник
comment
Можете ли вы временно заменить вызовы scanf жестко заданным целым числом?   -  person Anthony    schedule 01.06.2013
comment
Я пробовал так делать, но результат тот же.   -  person    schedule 01.06.2013


Ответы (2)


Я считаю, что GLib GHashTable принимает только ключи, являющиеся указателями. Он не принимает целочисленные ключи. Когда вы создаете хеш-таблицу с помощью ключевой функции g_int_hash, вам нужно получать из нее данные, используя указатели на объекты gint, а не просто целые числа. Итак, вместо

g_hash_table_lookup(h, m)

пытаться

g_hash_table_lookup(h, g_new(gint, 1))

См. http://blog.sensecodons.com/2012/01/glib-ghashtable-and-gdirecthash.html

person Lee Daniel Crocker    schedule 01.06.2013
comment
Я только что отредактировал сообщение, теперь вставка — это `g_hash_table_insert(h, &k, val);`, а поиск — g_hash_table_lookup(h, &m);. Тем не менее, все равно получаю тот же результат. - person ; 01.06.2013
comment
Переменная k выходит за пределы области видимости в конце f1(), поэтому ее адрес больше недействителен. Вам придется использовать адрес постоянно выделенного int. Вы также можете рассмотреть возможность использования g_direct_hash. - person Lee Daniel Crocker; 01.06.2013
comment
Итак, означает ли это, что если я хочу найти что-то в хеш-таблице glib, мне нужно использовать тот же точный объект, который использовался в качестве ключа при помещении элемента туда? - person ; 01.06.2013
comment
Думаю, теперь я это понимаю. По-видимому, glib не хранит копию ключа в структуре данных хеш-таблицы, он хранит только указатель на ключ. - person ; 01.06.2013
comment
Зависит от аргумента хеш-функции, который вы передаете, но в целом да. Похоже, вам действительно нужен здесь g_direct_hash. Примечание: хэш-таблица хранит только указатель на значение, а также на ключ, поэтому он также должен быть постоянным или скопированным. - person Lee Daniel Crocker; 01.06.2013
comment
Выполнение g_hash_table_lookup(h, g_new(gint, 1)); будет течь int-указатель. Вы можете настроить хэш-таблицу для автоматического освобождения ключа и значения, которые используются при вставке, но для поиска это просто приведет к утечке. Вместо этого выполните GINT_TO_POINTER. - person Havard Graff; 26.07.2013

Вы должны использовать макрос преобразования GINT_TO_POINTER, см. здесь: https://developer.gnome.org/glib/2.34/glib-Type-Conversion-Macros.html

so:

#include <glib.h>
#include <stdio.h>

GHashTable *h;
char val[]  = {'H', 'E', 'L', 'L', 'O',0};

void f1()
{
   int k;
   scanf("%d", &k);
   g_hash_table_insert(h, GINT_TO_POINTER(k), val);
}

void f2()
{
   int m;
   f1();
   scanf("%d", &m);
   gpointer *p = g_hash_table_lookup(h, GINT_TO_POINTER(m));
   printf("%s\n", (const char*)p);
}

int main()
{
   h = g_hash_table_new(g_int_hash, g_int_equal);
   f2();
   return 0;
}
person Havard Graff    schedule 16.07.2013
comment
Использование GINT_TO_POINTER для ключа и g_int_hash/g_int_equal для хеш-функций/поиска вызовет segfault. И g_int_hash, и g_int_euqal попытаются удалить указатель, и на самом деле это не указатель (спасибо GINT_TO_POINTER). Вы должны использовать g_direct_hash / g_direct_equal в вызове g_hash_table_new. - person flihp; 28.12.2016