Requirements checklist
- One fixed buffer; no system allocator, ever — the buffer is everything.
alloc(size) -> ptr | NULL,free(ptr)— free takes no size, which forces per-block headers.- Alignment floor on returned pointers; out-of-memory returns NULL.
- State the single-threaded contract; latency over perfect utilization.
The model
[ header | payload ][ header | payload ] ... every byte in exactly one block header: size + allocated bit free(ptr) -> header at ptr - HDR free list: next/prev stored INSIDE free payloads (costs nothing) alloc: search -> split (respect MIN_SPLIT) -> mark, return payload free: mark free -> coalesce with adjacent free neighbor(s)
Invariants (say them)
- Header accounting includes overhead —
alloc(16)consumes more than 16. - Every byte of the buffer belongs to exactly one block, always.
- Free-list membership ≡ block is free; no third state.
- A split never produces a block smaller than a header + minimum payload.
Complexity facts
- First-fit alloc: O(free blocks); best-fit: O(free blocks), full scan, tighter fits, more splinters.
- free: O(1); backward merge O(1) only with a footer/boundary tag, else a walk.
- Segregated lists approach O(1) — the named upgrade, bought with per-class bookkeeping.
The five report dimensions, for this problem
- Requirements & interface — caught what free-takes-no-size forces; pinned alignment and failure semantics unprompted.
- Core design & invariants — header format, free storage inside free blocks, split minimum, coalescing mechanism with its honest cost.
- Extension probe — name the invariant under attack, trace the concrete failure, cost the fix ladder.
- Complexity honesty — every O() with its because; no "O(1)" for a scan.
- Communication — arithmetic walked on real numbers, not asserted.
Ready? Sit the live mock → — the interviewer will run a twist this chapter deliberately hasn't shown you.