Reputation: 17
Getting some segfault on the following algorithm to add an element to the correct bucket in a hashtable.
My structures are basic:
struct kv {
char* key;
unsigned val;
struct kv* next;
};
struct hashtable {
struct kv** table;
unsigned size;
};
And my buggy function:
struct kv* ht_find_or_put(char* word, unsigned value,
struct hashtablet* hashtable,
unsigned (*hash)(char*))
{
unsigned index = hash(word) % hashtable->size;
struct kv* ke = malloc(sizeof (struct kv));
for (ke = hashtable->table[index]; ke != NULL; ke = ke->next)
{
if (strcmp(ke->key, word) == 0)
return ke;
}
if (ke == NULL)
{
ke->key = word;
ke->val = value;
ke->next = hashtable->table[index];
hashtable->table[index] = ke;
}
return ke;
}
I know I haven't added yet all the tests (if malloc failed and such) just trying to debug this particular problem...
I'm allocating my table as such:
struct hashtable* hashtable_malloc(unsigned size)
{
struct hashtable *new_ht = malloc(sizeof(struct hashtable));
new_ht->size = size;
new_ht->table = malloc(sizeof(struct kv) * size);
for(unsigned i = 0; i < size; i++)
new_ht->table[i] = NULL;
return new_ht;
}
Any sort of help will greatly be appreciated. I'm only starting to learn.
Upvotes: 0
Views: 254
Reputation: 137382
The first issue is a memory leak, e.g. - you allocate memory using malloc, but than loses the reference to it, as you override the pointer:
// allocate memory
struct kv* ke = malloc(sizeof (struct kv));
// lose the reference
// VVVVVVVVVVV
for (ke = hashtable->table[index]; ke != NULL; ke = ke->next)
The second issue, which probably causes the segfault, is that you try to de-reference a null pointer:
if (ke == NULL)
{
// ke is NULL, you can't de-reference it
ke->key = word;
ke->val = value;
ke->next = hashtable->table[index];
hashtable->table[index] = ke;
}
The solution will be, IMHO, to allocate and put the new element, only upon failure to find it:
struct kv* ht_find_or_put(char* word, unsigned value, struct hashtablet* hashtable, unsigned (*hash)(char*))
{
unsigned index = hash(word) % hashtable->size;
struct kv* ke;
// first we try to find the node
for (ke = hashtable->table[index]; ke != NULL; ke = ke->next)
{
if (strcmp(ke->key, word) == 0)
return ke;
}
// didn't find it - lets create and put a new one.
if (ke == NULL)
{
ke = malloc(sizeof (struct kv));
// later add a check if the allocation succeded...
ke->key = word;
ke->val = value;
ke->next = hashtable->table[index];
hashtable->table[index] = ke;
}
return ke;
}
Since I didn't want to introduce entirely new code, that would just confuse you, I made the minimal changes to the original code.
Upvotes: 1