K&R2 exercise 6-5-2

2026-10-11

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HASHSIZE 101

struct nlist {              /* table entry */
    struct nlist *next;     /* next entry in chain */
    char *name;             /* defined name */
    char *defn;             /* replacement text */
};

static struct nlist *hashtab[HASHSIZE];

unsigned hash(char *s)
{
    unsigned hashval;
    for (hashval = 0; *s != '\0'; s++)
        hashval = *s + 31 * hashval;
    return hashval % HASHSIZE;
}

struct nlist *lookup(char *s)
{
    struct nlist *np;
    for (np = hashtab[hash(s)]; np != NULL; np = np->next)
        if (strcmp(s, np->name) == 0)
            return np;
    return NULL;
}

struct nlist *install(char *name, char *defn)
{
    struct nlist *np;
    unsigned hashval;

    if ((np = lookup(name)) == NULL) {          /* not found */
        np = malloc(sizeof(*np));
        if (np == NULL || (np->name = strdup(name)) == NULL)
            return NULL;
        hashval = hash(name);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    } else
        free(np->defn);                          /* replace old definition */
    if ((np->defn = strdup(defn)) == NULL)
        return NULL;
    return np;
}

/* undef: remove name and its definition from the table.
   Returns 1 if removed, 0 if the name was not found. */
int undef(char *name)
{
    struct nlist *np, *prev = NULL;
    unsigned h = hash(name);

    for (np = hashtab[h]; np != NULL; prev = np, np = np->next)
        if (strcmp(name, np->name) == 0) {
            if (prev == NULL)
                hashtab[h] = np->next;   /* removing the head of the chain */
            else
                prev->next = np->next;   /* bypass the node */
            free(np->name);
            free(np->defn);
            free(np);
            return 1;
        }
    return 0;
}

int main(void)
{
    install("IN", "1");
    install("OUT", "0");

    printf("IN before undef: %s\n", lookup("IN") ? lookup("IN")->defn : "(none)");
    undef("IN");
    printf("IN after undef:  %s\n", lookup("IN") ? lookup("IN")->defn : "(none)");
    printf("OUT still there: %s\n", lookup("OUT") ? lookup("OUT")->defn : "(none)");
    return 0;
}

win@DESKTOP-MEIH88T:~/webdev-projects$  gcc -Wall -Wextra c-c.c -o c-c
win@DESKTOP-MEIH88T:~/webdev-projects$ ./c-c
IN before undef: 1
IN after undef:  (none)
OUT still there: 0