In this article
Before you start
This page is one prompt from the machine coding rounds guide to industry coding, and it needs only a little C.
Why interviewers ask this
The aligned malloc prompt is a small question that exposes whether a candidate understands what a pointer really is. Candidates have reported the prompt align_Malloc(int size, int align) in interviews at NVIDIA; no public source confirms how any company scores it. The argument order (size first, alignment second) matches Microsoft's undefined, while the C standard function takes alignment first, so ask which order the interviewer wants.
A weak answer calls malloc and rounds the pointer, then returns it. That leaks memory, because the original block can never be freed. A strong answer shows three things: the size of the over-allocation and why, a bit trick that works only for powers of two, and a paired free that recovers the original pointer. A Staff-level answer adds when not to write this at all, because the platform already ships tested functions, and what changes at the edges: zero size, tiny alignments and arithmetic overflow.
Aligned malloc implementation from first principles
- Memory alignment
- Memory alignment is a rule that requires the address of a piece of data to be a multiple of some number, usually a power of two, so the processor can load it in fewer or simpler memory accesses than it needs for an address that straddles a boundary.
- Over-aligned allocation
- An over-aligned allocation is a block of memory whose address must be a multiple of a number larger than the alignment ordinary
mallocprovides, for example a cache line or a virtual-memory page, so that the block starts exactly on that boundary. - Alignment mask
- An alignment mask is the bit pattern formed by inverting the alignment minus one, so that a bitwise AND with it clears the low bits of an address and rounds the address down to a multiple of a power-of-two alignment.
In plain words
Picture a car park whose bays start every 64 metres. You must park at the start of a bay, but the attendant hands you a spot at some random place. So you rent a longer stretch than you need, walk forward to the first bay start, and park there. Then you pin a note at the bay's entrance saying where your rental really began. When you leave, the note tells the attendant which rental to close.
The analogy breaks in one place. A real car park has a fixed layout, but malloc may return a different address each time.
In one precise sentence, an aligned allocator asks malloc for a larger block. It finds the first aligned address inside it. It records the block's true start next to that address.
How aligned is plain malloc?
Plain malloc is already aligned, but only for ordinary object types. cppreference says regular malloc returns memory suitable for any object type, which in practice means alignof(max_align_t). A jemalloc maintainer's comment says the same of the plain allocation functions. The cppreference page names the reasons to ask for more: cache lines, vector instructions and virtual-memory page boundaries. An Association of C and C++ Users (ACCU) Overload article notes that malloc is likely to return an address that is 8- or 16-byte aligned, so a block can straddle a 64-byte boundary.
Step 1: Request extra bytes from malloc
The aligned allocator requests size plus alignment minus one plus sizeof(void *) bytes from malloc. Call the returned address the raw pointer. The three parts have three jobs: size is what the caller wants, the pointer size is room for a note, and alignment minus one is the most you may have to skip to reach a boundary.
Why alignment minus one? Boundaries are alignment bytes apart, so in any run of that many consecutive addresses exactly one is aligned. Skipping at most alignment minus one bytes always lands on a boundary, and the extra bytes you asked for leave size bytes after it.
Input: size and align. Output: a raw pointer to a larger block. For size 100 and alignment 64, the request is 171 bytes.1 You now have enough room; the next step finds the address to return.
Step 2: Round the address up with a bit mask
The allocator rounds the address up to a multiple of the alignment by adding alignment minus one and then clearing the low bits with the alignment mask. First step past the raw pointer by sizeof(void *) bytes, so a pointer-sized slot will fit before the result. Call that address start. Then compute (start + align - 1) & ~(align - 1).
This works only for powers of two. A power of two such as 64 has a single one bit, so 63 is a run of six ones, and clearing those six bits snaps an address down to a multiple of 64. The check a != 0 && (a & (a - 1)) == 0 accepts 1, 8, 64 and 4096 and rejects 0, 3 and 96.1
Do the arithmetic on an unsigned integer type wide enough to hold a pointer, uintptr_t, which C11 defines as optional but which mainstream compilers provide. A raw pointer of 0x1008 becomes start 0x1010 and rounds up to 0x1040.1
Step 3: Store the original pointer just before the aligned address
The allocator stores the raw pointer in the sizeof(void *) bytes immediately before the address it returns. Because start is the raw pointer plus the pointer size, and the aligned address is never below start, that slot always lies inside the block you own. For the example, the slot is at 0x1038, and the raw pointer 0x1008 is written there.1
This is the answer to the hook. The caller only ever sees the aligned address, but free must receive the address malloc returned. Microsoft's documentation says to release such blocks with _aligned_free and warns that plain free does not reclaim the aligned memory correctly and can cause hard-to-diagnose bugs. The aligned address may sit in the middle of the block, and passing it to free is undefined.
Input: raw and aligned addresses. Output: the aligned address, with a note behind it. You now hold both addresses; the last step uses the note.
Step 4: The matching free reads the stored pointer back
The aligned free function reads the pointer stored just before the address it is given and passes that stored pointer to free. Nothing else is needed: no table, no search, and no extra bookkeeping. Treat a null argument as a no-op, as free does.
#include <stdint.h>
#include <stdlib.h>
void *align_malloc(size_t size, size_t align) {
if (align == 0) return NULL; /* zero is not a valid alignment */
if (align < sizeof(void *)) align = sizeof(void *); /* slot must be aligned too */
if (align & (align - 1)) return NULL; /* not a power of two */
if (size > SIZE_MAX - align - sizeof(void *)) return NULL; /* overflow guard */
void *raw = malloc(size + align - 1 + sizeof(void *));
if (!raw) return NULL;
uintptr_t start = (uintptr_t)raw + sizeof(void *);
uintptr_t aligned = (start + align - 1) & ~(uintptr_t)(align - 1);
((void **)aligned)[-1] = raw; /* note behind the block */
return (void *)aligned;
}
void align_free(void *p) {
if (p) free(((void **)p)[-1]); /* free the raw pointer */
}The listing follows the four steps in order, with four small guards the steps did not need: a zero check, a minimum alignment, a power-of-two check and an overflow check. Time and extra space are constant, apart from the call to malloc itself.
Step-by-step description
- Ask malloc for extra bytes.
- Add, then mask the low bits.
- Save the raw pointer behind it.
- Free the stored pointer.
- The address is rounded up to a multiple of the alignment.
- The raw pointer is stored just before the aligned address.
- The aligned free reads the stored pointer and passes it to free.
Knowing it is half the job. Saying it is the other half.
Interview Clozo is an AI interview copilot for real interview rounds: it hears the question and puts a strong answer on your screen, and you say it in your own words. See the features or how it works.
Start Free Trial →Worked example
The example asks for size 100 and alignment 64 on a 64-bit machine, where a pointer is 8 bytes, and assumes malloc returns the raw address 0x1008 (an illustrative address).1 The request is 100 + 63 + 8 = 171 bytes. The slot sits after the raw pointer, so start is 0x1010. Adding 63 gives 0x104F, and clearing the low six bits with the mask 0x3f inverted gives 0x1040, the address returned to the caller. The unused bytes between the raw address and the aligned address are called padding, and here that is 56 bytes.1
| Quantity | Value (computed or illustrative) |
|---|---|
Raw address from malloc (illustrative) | 0x1008 |
start (raw plus 8) | 0x1010 |
| Aligned address returned | 0x1040 |
| Where the raw pointer is stored | 0x1038 |
| Padding before the aligned address | 56 bytes |
| Bytes requested for size 100, alignment 64 | 171 |
| Spare bytes after the 100-byte block | 15 |
| Largest padding when the raw address is a multiple of 8 | 64 bytes |
The 15 spare bytes are 171 minus the 56 padding bytes minus the 100 requested, so the block fits inside the allocation.1
Padding changes with the raw address. Stepping the raw address from 0x1000 to 0x1038 in 8-byte steps, padding falls from 64 bytes to 8.1 A raw address that is already aligned still pays 64 bytes, because the pointer slot must fit before the returned address, which pushes the result to the next boundary.
Text description of the diagram
- A raw address of 0x1008 gets 56 bytes of padding.
- Padding falls from 64 bytes to 8 across the sweep.
Trade-offs and edge cases
The hand-written approach trades memory for portability: it wastes up to roughly an alignment's worth of bytes per block and works on any platform with malloc. The platform functions hide that overhead and handle the edge cases, so a real program should prefer them.
The three common ones differ, as the table below shows. The C11 aligned_alloc(alignment, size) needs a size that is an integral multiple of the alignment and returns a null pointer when the alignment is invalid or unsupported, according to cppreference; C11 as published left that case undefined, and defect report 460 corrected it. The Portable Operating System Interface (POSIX) function undefined requires a power-of-two multiple of sizeof(void *), returns invalid argument (EINVAL) or out of memory (ENOMEM) as an error code, and its block is released with plain free.
Text description of the diagram
- aligned_alloc takes alignment first and size second.
- _aligned_malloc takes size first and alignment second.
- Only _aligned_malloc needs its own free function.
Edge cases a reviewer probes:
- Alignment below pointer size. An alignment of 1, 2 or 4 could put the slot at an unaligned address, so raise the alignment to
sizeof(void *)first. - Alignment that is not a power of two. The mask trick returns wrong addresses, so reject it. Documentation and behaviour can differ: the ACCU article reports that glibc
memalignaccepted any alignment and silently rounded it up to the next power of two, despite its man page. - Size arithmetic overflow. A huge
sizemakes the sum wrap around to a small number, so check before adding. - Zero size. POSIX leaves the result implementation-defined, and Microsoft treats it as an invalid parameter, so decide and state the behaviour.
For other from-scratch design-and-implement prompts, the low level design question list collects more of the same style.
How to answer it in an interview
Implement an aligned malloc. How does it work, and what does the free look like?
I over-allocate with malloc: size plus alignment minus one plus room for one pointer. I step past that pointer slot, then round the address up to a multiple of the alignment with an add and a mask, which only works because the alignment is a power of two. I store the original malloc pointer in the slot just before the returned address. My aligned free reads that slot and calls free on it. I reject bad alignments and guard the size overflow, and in production I would call aligned_alloc or posix_memalign instead.
The spoken structure: say the request size and why, show the round-up, name where the original pointer lives, then give the matching free and the trade-off.
Common mistakes
- "I return the rounded pointer and call
freeon it later." (wrong) The rounded address may sit in the middle of the block, sofreegets an address it never issued. (right) "The aligned free reads the stored raw pointer and frees that." - "I round the raw pointer down with the mask." (wrong) Rounding down can return an address before the block
mallocgave you, outside memory you own. (right) "I add alignment minus one, then clear the low bits, which rounds up." - "Any alignment works with the mask." (wrong) The trick needs a power of two. (right) "I test
a != 0 && (a & (a - 1)) == 0and fail otherwise." - "Plain
mallocreturns unaligned memory." (wrong) It is aligned for any object type; it is not aligned for a cache line or page. (right) "mallocis aligned toalignof(max_align_t), so I only need this for larger boundaries."
Follow-up questions
How do you implement align_Malloc taking size and alignment parameters?
Over-allocate by size + align - 1 + sizeof(void *), round the address after the pointer slot up with (start + align - 1) & ~(align - 1), store the raw pointer just before the result, and return it. Pair it with an align_free that frees the stored pointer.
Why must the aligned free get the original pointer back?
The address you returned is somewhere inside the block malloc issued, and free is only defined for the address malloc returned. Microsoft's runtime has a separate _aligned_free for this reason.
What should the function do if the alignment is not a power of two?
Return a null pointer. The mask depends on a single one bit; POSIX and Microsoft both require a power of two, and posix_memalign reports EINVAL.
How do you implement a memory manager for N bytes with malloc(k), free and coalescing?
Keep a list of free blocks, each with a size header. On malloc(k), take the first block that fits and split off the remainder. On free, mark the block free and merge it with free neighbours so large requests can still succeed. It is a different problem; see the machine coding rounds guide for how such prompts are scoped.
Why not just call aligned_alloc or posix_memalign?
In production, you should: they are tested, handle the edge cases, and manage any bookkeeping for you (on Windows that is why _aligned_free exists). In an interview the point is to show you understand what such a function must do. The least recently used (LRU) cache implementation, the in-memory database assessment and time-to-live (TTL) caches and time-based key-value stores pose the same style of from-scratch prompt.
- Plain
mallocis aligned for any object type; an aligned malloc is for larger boundaries such as a cache line. - Request size plus alignment minus one plus pointer size, round up with a mask, and store the raw pointer behind the result.
- The mask works only for powers of two, so reject any other alignment.
- The aligned free must pass the stored raw pointer to
free. - Platform calls differ in argument order and in how the block is released; prefer them in production.
Sources
- aligned_alloc - cppreference.com (C reference) — cppreference community wiki (undated; text read on a mirror copy on 2026-10-26), 26 Oct 2026
- posix_memalign - POSIX.1-2008 (2018 edition) — The Open Group (IEEE Std 1003.1; undated; accessed 2026-10-26), 26 Oct 2026
- _aligned_malloc - C runtime library reference — Microsoft Learn (undated; accessed 2026-10-26), 26 Oct 2026
- Drawing a Line Under Aligned Memory — ACCU Overload issue 174, 2023 (accessed 2026-10-26), 26 Oct 2026
- malloc alignment behaviour (jemalloc issue 1533) — GitHub, jemalloc maintainers (accessed 2026-10-26), 3 Jul 2019