Проблема с указателем при вставке и поиске HashTable - PullRequest
0 голосов
/ 25 апреля 2019

Я использую собственную C-реализацию структур данных из github.Документация здесь: http://fragglet.github.io/c-algorithms/doc/

Я впервые использую низкоуровневое использование HashTable, и у меня возникают проблемы с указателем при восстановлении ранее введенных значений.

Мой код простопростой тест с только необходимым для вставки и восстановления данных.

#include "list.h"
#include "hash-table.h"
#include <stdio.h>

//typedef unsigned int (*HashTableHashFunc)(HashTableKey value);
unsigned int hashFunc(HashTableKey v_key)
{
    unsigned int *key = (unsigned int *)v_key;
    return *key % 20;
}

//typedef int (*HashTableEqualFunc)(HashTableKey value1, HashTableKey value2);
int equalFunc(HashTableKey value1, HashTableKey value2)
{
    int *key1 = (int *)value1;
    int *key2 = (int *)value2;
    return *key1 == *key2;
}

int main(int argc, char const *argv[])
{
    HashTable *mapMatrices;
    //ListEntry *posicionListaPeticiones;

    mapMatrices = hash_table_new(hashFunc, equalFunc);

    for (int i = 0; i < 10; i++)
    {
        int key = i;
        int value = i * 200;
        int stat = hash_table_insert(mapMatrices, &key, &value);
        if (!stat)
            printf("Error inserting key %i with value %i\n", key, value);
        else
            printf("Inserted key %i with value %i\n", key, value);
    }

    for (int i = 0; i < 10; i++)
    {
        int key = i;
        void *v_value = hash_table_lookup(mapMatrices, &key);
        int value = *(int *)v_value;
        printf("Key pointer %x : Value pointer %x\n", &key, &value);
    }
}

Это мой вывод, если я печатаю адреса данных

Inserted key 0 with value 0
Inserted key 1 with value 200
Inserted key 2 with value 400
Inserted key 3 with value 600
Inserted key 4 with value 800
Inserted key 5 with value 1000
Inserted key 6 with value 1200
Inserted key 7 with value 1400
Inserted key 8 with value 1600
Inserted key 9 with value 1800
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358
Key ed75a354 : Value pointer ed75a358

И это то, что происходит после того, как я пытаюсьраспечатать содержимое моих адресов

printf("Key %i : Value pointer %i\n", key, value);
Inserted key 1 with value 200
Inserted key 2 with value 400
Inserted key 3 with value 600
Inserted key 4 with value 800
Inserted key 5 with value 1000
Inserted key 6 with value 1200
Inserted key 7 with value 1400
Inserted key 8 with value 1600
Inserted key 9 with value 1800
Segmentation fault (core dumped)

Код реализации HashTable

HashTable *hash_table_new(HashTableHashFunc hash_func,
                          HashTableEqualFunc equal_func)
{
    HashTable *hash_table;

    /* Allocate a new hash table structure */

    hash_table = (HashTable *) malloc(sizeof(HashTable));

    if (hash_table == NULL) {
        return NULL;
    }

    hash_table->hash_func = hash_func;
    hash_table->equal_func = equal_func;
    hash_table->key_free_func = NULL;
    hash_table->value_free_func = NULL;
    hash_table->entries = 0;
    hash_table->prime_index = 0;

    /* Allocate the table */

    if (!hash_table_allocate_table(hash_table)) {
        free(hash_table);

        return NULL;
    }

    return hash_table;
}

int hash_table_insert(HashTable *hash_table, HashTableKey key,
                      HashTableValue value)
{
    HashTableEntry *rover;
    HashTablePair *pair;
    HashTableEntry *newentry;
    unsigned int index;

    /* If there are too many items in the table with respect to the table
     * size, the number of hash collisions increases and performance
     * decreases. Enlarge the table size to prevent this happening */

    if ((hash_table->entries * 3) / hash_table->table_size > 0) {

        /* Table is more than 1/3 full */

        if (!hash_table_enlarge(hash_table)) {

            /* Failed to enlarge the table */

            return 0;
        }
    }

    /* Generate the hash of the key and hence the index into the table */

    index = hash_table->hash_func(key) % hash_table->table_size;

    /* Traverse the chain at this location and look for an existing
     * entry with the same key */

    rover = hash_table->table[index];

    while (rover != NULL) {

        /* Fetch rover's HashTablePair entry */

        pair = &(rover->pair);

        if (hash_table->equal_func(pair->key, key) != 0) {

            /* Same key: overwrite this entry with new data */

            /* If there is a value free function, free the old data
             * before adding in the new data */

            if (hash_table->value_free_func != NULL) {
                hash_table->value_free_func(pair->value);
            }

            /* Same with the key: use the new key value and free
             * the old one */

            if (hash_table->key_free_func != NULL) {
                hash_table->key_free_func(pair->key);
            }

            pair->key = key;
            pair->value = value;

            /* Finished */

            return 1;
        }

        rover = rover->next;
    }

    /* Not in the hash table yet.  Create a new entry */

    newentry = (HashTableEntry *) malloc(sizeof(HashTableEntry));

    if (newentry == NULL) {
        return 0;
    }

    newentry->pair.key = key;
    newentry->pair.value = value;

    /* Link into the list */

    newentry->next = hash_table->table[index];
    hash_table->table[index] = newentry;

    /* Maintain the count of the number of entries */

    ++hash_table->entries;

    /* Added successfully */

    return 1;
}

HashTableValue hash_table_lookup(HashTable *hash_table, HashTableKey key)
{
    HashTableEntry *rover;
    HashTablePair *pair;
    unsigned int index;

    /* Generate the hash of the key and hence the index into the table */

    index = hash_table->hash_func(key) % hash_table->table_size;

    /* Walk the chain at this index until the corresponding entry is
     * found */

    rover = hash_table->table[index];

    while (rover != NULL) {
        pair = &(rover->pair);

        if (hash_table->equal_func(key, pair->key) != 0) {

            /* Found the entry.  Return the data. */

            return pair->value;
        }

        rover = rover->next;
    }

    /* Not found */

    return HASH_TABLE_NULL;
}

1 Ответ

1 голос
/ 26 апреля 2019

Происходит путаница с указателями.Если вы замените:

for (int i = 0; ...

на

int i;
for (i = 0; ...

для первого цикла в основном и на:

для (i = 0; ... * 1009)*

во втором цикле вы получите ожидаемый результат.

Если вы добавите эту строку к вашему equFunc:

fprintf(stderr,"cmp %p/%d, %p/%d\n", key1, *key1, key2, *key2);

, вы заметите, что два параметраequalFunc всегда одинаковы - они фактически указывают на вашу локальную переменную «i», поэтому это не сработало с двумя отдельными значениями «i».

Момент с отладчиком покажет, что:

void *v_value = hash_table_lookup(mapMatrices, &i);

возвращает NULL в вашем источнике [т.е. не найден], но вы все равно продолжаете разыменовывать его.

Чтобы сделать вашу программу правильной , выВероятно, вам следует передавать ключ по значению, а не по ссылке:

int stat = hash_table_insert(mapMatrices, (int *)i, (int *)value);
...
void *v_value = hash_table_lookup(mapMatrices, (int *)i);
int value = (int )v_value;
...
/* equalFunc: */
return (int)value1 == (int)value2;

Но по гигиеническим причинам используйте intptr_t и посторонние приведения, чтобы злой бог неопределенного поведения не сжег ваш дом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...