Section 6.6 of K&R discusses a hash table using a linked list.
In short, a hash table is an array of pointers. The pointers point to a linked list. The linked list is a struct that looks like:
struct nlist { /* table entry: */
struct nlist *next; /* next entry in chain */
char *name; /* defined name */
char *defn; /* replacement text */
};
The name is hashed, and this hash determines the index in the table. The chapter then shows code to add a name/defn pair to the table:
struct nlist *install(char *name, char *defn) {
struct nlist *np;
unsigned hashval;
if ((np = lookup(name)) == NULL) { /* not found */
np = (struct nlist *) malloc(sizeof(*np));
if (np == NULL || (np->name = strdup(name)) == NULL)
return NULL;
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval] = np;
} else /* already there */
free((void *) np->defn); /*free previous defn */
if ((np->defn = strdup(defn)) == NULL)
return NULL;
return np;
}
Everything makes sense except for the following 2 lines:
np->next = hashtab[hashval];
hashtab[hashval] = np;
When I try to understand this, I keep coming to the conclusion that the list now links back to itself and if you try to traverse the linked list it will be like a dog chasing its own tail. I would expect the code to set np->next to NULL.
What am I not understanding? How come this code works ?
It results in the new value being inserted at the beginning of the list.
So it goes from:
hashtab[hashval] --> original_list
to:
hashtab[hashval] --> original_list
np->next --> original_list
to:
hashtab[hashval] --> *np
np->next --> original_list
The golden rule is, if linked-list code doesn't make sense, always draw out a diagram!
hashtab[hashval] is a pointer, not a value. It is a pointer to the address in memory where the first element of that particular row in the pointer table (static struct nlist *hashtab[HASHSIZE]) resides. np and np->next are also pointers. So here is what happens in these two lines: First line: The pointer of the first element in that row of the table is copied into np->next. np->next now points at the address in memory where the first element of that row used to point. Second line: The pointer to the address in memory where the new *np resides is now copied into the pointer variable hastab[hashval]. hastab[hashval] now once again becomes the pointer to where the first element of that table row resides. So, just as Oli wrote, the new *np is inserted at the beginning of that particular row in the table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With