Free preview

Why this matters: the memory allocator is the centerpiece of the systems-programming set — the problem that asks you to build the thing every other program takes for granted. It also contains the single most famous forcing requirement in this flavor of interview, and whether you notice it during the requirements act decides the shape of everything you write afterward.

The prompt, as given

Implement a memory allocator.

Your allocator is handed one contiguous buffer of raw memory at initialization — that buffer is all the memory it will ever have. Callers request blocks of arbitrary sizes and return them in any order, and your allocator must service both without ever calling the system allocator.

One buffer, arbitrary sizes, arbitrary order. Unlike the arena — where the contract's refusal was the design — this allocator must support the full general contract: individual allocation and individual free, interleaved however callers please. That generality is exactly what you'll pay for, and the requirements conversation is where you find out the price.

The questions, and why each one matters

"What is the interface — and what does free receive?" Ask it precisely, because the answer is the forcing requirement Foundations lesson 02 taught with this very example: alloc(size) returns a pointer or NULL, and free(ptr) receives only the pointer. No size. The allocator must recover a block's size from its pointer alone, and there is only one place that information can live: written down by the allocator itself, adjacent to the block. Headers are not a design choice; they're the consequence of this sentence. Catching that live — saying "no size on free means I'm storing per-block metadata" — is one of the strongest signals this problem offers.

"How big is the buffer, and what's the size range of requests?" A fixed 1 MiB region serving requests from tens of bytes to tens of kilobytes tells you the allocator must handle mixtures — many small blocks alongside occasional large ones — which is where placement policy starts to matter.

"What alignment must returned pointers have?" At least 8 bytes. This quietly helps the design: if all block sizes are multiples of 8, the low bits of any stored size are always zero — free real estate for flags.

"What happens when a request can't be satisfied?" Return NULL. A refusal path, stated up front, exactly like the parking lot's full-lot answer.

"One thread or many?" Single-threaded. We take that as a stated design constraint for this chapter and build accordingly — a deliberate scoping decision to say out loud, the same way you'd name any assumption you're designing under.

"What matters more — speed or tight packing?" Latency over utilization, says our interviewer. That one preference will later pick the placement policy for us, which is why it's worth asking even when it sounds abstract: policies need objectives.

The requirement set this chapter builds against

buffer        one contiguous region, 1 MiB, given at init;
              no system calls, ever — the buffer is everything
interface     alloc(size) -> pointer | NULL
              free(ptr)   -> takes ONLY the pointer     <- forces headers
sizes         16 bytes to 64 KiB, any mix, any order
alignment     returned pointers >= 8-byte aligned
failure       out of memory -> NULL
threading     single-threaded (stated constraint for this design)
objective     latency matters more than perfect utilization

As with every chapter: a live interviewer's answers may differ — a different buffer size, a different objective, stricter alignment. The conversation is the skill. But the free-takes-no-size answer is near-universal in this problem, because the design it forces is the design the problem exists to examine.

Key takeaway

The general allocator's contract — arbitrary sizes, arbitrary order, and a free that receives only the pointer — forces per-block metadata: the allocator must write down what it will later need to read back. Pin the buffer, the size range, alignment, the NULL path, the single-threaded scope as a named constraint, and the latency-over-utilization objective; the next lesson turns those answers into a block format and a policy.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue