// lesson: put-and-get

Put and Get

Time to assemble the map itself: a heap-allocated array of bucket heads plus a length counter.

struct hashmap {
	struct hm_entry **buckets;  /* array of nbuckets chain heads */
	size_t nbuckets;
	size_t len;                 /* number of stored entries */
};

hm_get is the two helpers from last lesson glued together: hash, index, walk the chain โ€” the whole lookup is just this pipeline:

hm_get(m, "ada")fnv1a("ada") โ†’ 0xโ€ฆ% nbuckets โ†’ bucket indexwalk chain, strcmp each key&entry.value (NULL if absent)
hm_get(m, "ada")fnv1a("ada") โ†’ 0xโ€ฆ% nbuckets โ†’ bucket indexwalk chain, strcmp each key&entry.value (NULL if absent)

hm_put has more decisions in it:

  • Overwrite, don't duplicate. If the key already exists, replace its value in place; len doesn't change. Only a genuinely new key allocates a node and bumps len.
  • Own your keys. The caller's string may be a stack buffer that dies at the next }. The map must copy the key into memory it owns (allocate strlen + 1 bytes and copy โ€” this is what non-standard strdup does).
  • Report allocation failure. malloc returns NULL when memory runs out; a library that crashes instead of returning an error is a library you can't ship. Return 0 on success, -1 on failure.

Returning int * (a pointer to the stored value) from hm_get instead of int kills two birds: NULL cleanly signals "not found", and callers can update a value through the pointer without a second lookup.

โ€บ The Core API

15 pts

Implement hm_put and hm_get. The starter gives you working fnv1a, hm_new, bucket_index, and chain_find so the earlier building blocks don't need re-typing; new entries may go at the head of their chain (it's the easy spot).

Log in to submit a solution and earn points.