I am using hsearch_r function provided by GNU C library.
I see that while i can add elements into the HASH table using hsearch_r and passing the action as ENTER, i s
The source of hsearch_r can be found online.
If the key is in the table, the function returns with the found entry before checking the action, which means that adding an existing key behaves like finding it. (You could overwrite the value of the "found" struct after the call to hsearch(ADD)
and overwrite old values.)
The implementation isn't suited to element deletion. It maintains an array of buckets. Hash collision is handled by finding another empty bucket, so that the bucket index does not necessarily equal the hash code. When you insert two values with the same hash code, the second will get such a bucket where the hash code is not the bucket index.
When you now delete the first item and then try to find the second, it will not be found, because the "other" buckets are only considered when the "optimum" bucket where the hash code is the bucket index is full.
Besides the non-updating re-additions and the missing deletion option, there are other restrictions to hsearch_r
. For example, the maximum nuber of entries must be estimated beforehand and cannot be changed later. I think hsearch_r
is intended as a fast hash table for a limited range of applications. You might be better off with another, more general hash table implementation.
Alternatively, you could use a default data parameter that means "not present". The type of entry->data
is void *
, so NULL
is an obvious choice. The following data is a modification of the man pages's example with wrapper functions that have a more natural syntax than hsearch_r
:
#include
#include
#define _GNU_SOURCE
#define __USE_GNU
#include
#define NIL (-1L)
void hadd(struct hsearch_data *tab, char *key, long value)
{
ENTRY item = {key, (void *) value};
ENTRY *pitem = &item;
if (hsearch_r(item, ENTER, &pitem, tab)) {
pitem->data = (void *) value;
}
}
void hdelete(struct hsearch_data *tab, char *key)
{
ENTRY item = {key};
ENTRY *pitem = &item;
if (hsearch_r(item, FIND, &pitem, tab)) {
pitem->data = (void *) NIL;
}
}
long hfind(struct hsearch_data *tab, char *key)
{
ENTRY item = {key};
ENTRY *pitem = &item;
if (hsearch_r(item, FIND, &pitem, tab)) {
return (long) pitem->data;
}
return NIL;
}
int main()
{
char *data[] = {
"apple", "pear", "cherry", "kiwi",
"orange", "plum", "pomegranate", NULL
};
char **p = data;
struct hsearch_data tab = {0};
int i;
hcreate_r(10, &tab);
for (i = 0; i < 5; i++) hadd(&tab, data[i], i + 1L);
hdelete(&tab, "pear");
hadd(&tab, "cherry", 144);
while (*p) {
long value = hfind(&tab, *p);
if (value == NIL) {
printf("%s: NIL\n", *p);
} else {
printf("%s: %ld\n", *p, value);
}
p++;
}
hdestroy_r(&tab);
return 0;
}
Note: If you use ponters as data and the hash table owns that data, you must free
the data on destruction, but also when you overwrite existing values.