Search code examples
chashuthash

The method HASH_ADD does not add the new elements to the hash table. Using uthash.h


Based on the documentation found here, I wrote the following code in C:

adj_hash_table.h

typedef struct {
    int id_0;
    int id_1;
}id_t_;

typedef struct {
    id_t_ id;
    double value;
    UT_hash_handle hh;
}cell_t;

void add_(int id_0, int id_1, double value, cell_t *cells);
void free_table( cell_t *cells);
void main();

adj_hash_table.c

#include <stdio.h>
#include "uthash/src/uthash.h"
#include "adj_hash_table.h"

void add_(int id_0, int id_1, double value, cell_t *cells){

    cell_t l, *p;

    memset(&l, 0, sizeof(cell_t));
    l.id.id_0 = id_0;
    l.id.id_1 = id_1;
    HASH_FIND(hh, cells, &l.id, sizeof(id_t_), p); 

    if (p == NULL) {
        printf("Not found %d, %d\n", id_0, id_1);
        p = (cell_t *)malloc(sizeof *p);
        memset(p, 0, sizeof *p);
        p->id.id_0 = id_0;
        p->id.id_1 = id_1;
        HASH_ADD(hh, cells, id, sizeof(id_t_), p);
    }
    else
    {
        printf("Found %d, %d\n", id_0, id_1);
    }
    p->value = value;
}

void free_table( cell_t *cells){
    cell_t *p, *tmp;
    HASH_ITER(hh, cells, p, tmp) {
        HASH_DEL(cells, p);
        free(p);
    }
}

void main(){
    int nb_cells;
    cell_t *cells = NULL; 

    add_(0,0,1.0,cells);
    add_(0,1,2.0,cells);
    add_(0,0,3.0,cells);

    nb_cells=HASH_COUNT(cells);
    printf("number of cells: %d\n", nb_cells);

    free_table(cells);
}

When I compile it using: gcc -g -Wall -o adj_hash_table adj_hash_table.c and later run it using ./adj_hash_table, I get the following output:

Not found 0, 0
Not found 0, 1
Not found 0, 0
number of cells: 0

But I expect:

Not found 0, 0
Not found 0, 1
Found 0, 0
number of cells: 2

which makes me think that HASH_ADD is not working. The examples from here work fine for me. What am I doing wrong? Also, is my free_table method correct? Thanks !!


Solution

  • From the "Passing the hash pointer into functions" section of the referenced documentation:

    In the example above users is a global variable, but what if the caller wanted to pass the hash pointer into the add_user function? At first glance it would appear that you could simply pass users as an argument, but that won’t work right.

    You really need to pass a pointer to the hash pointer:

    The reason it’s necessary to deal with a pointer to the hash pointer is simple: the hash macros modify it (in other words, they modify the pointer itself not just what it points to).

    That is, you need to pass cell_t ** to your add_ function instead of cell_t * and then call the HASH macros with *cells.

    void add_(int id_0, int id_1, double value, cell_t **cells){
        ....
        HASH_FIND(hh, *cells, &l.id, sizeof(id_t_), p);
        ....
        HASH_ADD(hh, *cells, id, sizeof(id_t_), p);
    

    And calls would be:

    cell_t *cells = NULL; 
    add_(0,0,1.0,&cells);
    add_(0,1,2.0,&cells);
    add_(0,0,3.0,&cells);