Simplest hash trie (stores pointers, doesn't abuse call stack)

#include "stdio.h"
#include "stdlib.h"
 
typedef struct hash_t hash_t;
 
struct hash_t {
	hash_t* cont[128];
	void* user;
};
 
void hash_clear(hash_t* tree) {
	int i;
	for (i = 0; i < 128; i++) tree->cont[i] = NULL;
	tree->user = NULL;
}
 
hash_t* hash_new() {
	hash_t *tree;
	tree = malloc(sizeof(hash_t));
	hash_clear(tree);
	return tree;
}
 
#ifndef DONT_STACK
void* hash_get(hash_t* tree, const char* addr) {
	if (!(*addr)) return tree->user;
	return (!tree->cont[*addr] ? NULL : hash_get(tree->cont[*addr], addr+1));
}
#else
void* hash_get(hash_t* tree, const char* addr) {
	while (*addr) {
		if (!(tree = tree->cont[*addr])) return NULL;
		addr++;
	}
	return tree->user;
}
#endif
 
#ifndef DONT_STACK
void hash_set(hash_t* tree, const char* addr, void* value) {
	if (!(*addr)) tree->user = value;
	else hash_set((!tree->cont[*addr] ?
			(tree->cont[*addr] = hash_new()) : tree->cont[*addr]),
			addr+1, value);
}
#else
void hash_set(hash_t* tree, const char* addr, void* value) {
	hash_t *next;
	while (*addr) {
		next = tree->cont[*addr];
		if (!next) tree->cont[*addr] = next = hash_new();
		tree = next;
		addr++;
	}
	next->user = value;
}
#endif
 
int main() {
	hash_t root;
	hash_clear(&root);
 
	hash_set(&root, "abba", "rocks");
 
	printf("Abba - %s!\n", hash_get(&root, "abba"));
 
	return 0;
}