Question
In C, suppose you have a function memset_16aligned that requires a pointer aligned to a 16-byte boundary. If the pointer is not 16-byte aligned, the program may crash.
How can you:
- Allocate
1024bytes of memory and ensure the pointer passed tomemset_16alignedis aligned to a 16-byte boundary? - Free the memory correctly after
memset_16alignedfinishes?
Example skeleton:
{
void *mem;
void *ptr;
/* answer a) here */
memset_16aligned(ptr, 0, 1024);
/* answer b) here */
}
Short Answer
By the end of this page, you will understand what memory alignment means in C, why some functions require aligned pointers, how to manually create aligned memory using only standard library facilities, and how to free it safely afterward.
Concept
Memory alignment means storing data at addresses that are multiples of some value, such as 8 or 16. A pointer is 16-byte aligned if its address is divisible by 16.
This matters because:
- Some CPU instructions require aligned memory.
- Some low-level functions are written for performance and assume alignment.
- Misaligned access can be slower, or on some systems, invalid.
In this question, the key challenge is that the C standard library historically does not provide a portable aligned allocator in older C versions. That means if you must use only standard library tools like malloc and free, the usual technique is:
- Allocate a little more memory than you need.
- Move the returned pointer forward until it reaches the desired alignment.
- Keep the original pointer so you can still pass it to
freelater.
The important rule is:
freemust be called with the original pointer returned bymalloc.- You must not call
freeon the adjusted aligned pointer.
If you are using modern C, aligned_alloc exists in C11, but it has its own rules and is not available everywhere. Interview questions often expect you to know the manual technique because it works with basic standard allocation functions.
Mental Model
Think of malloc as giving you a parking lot starting point, but not necessarily one lined up exactly with a painted parking space boundary.
If you need a car parked exactly on every 16th line, you:
- reserve a little extra space,
- move forward to the next correct painted line,
- remember where the parking lot really began so you can return it properly later.
So:
mem= the real start of the allocated blockptr= the adjusted, aligned address you actually use
You work with ptr, but you free mem.
Syntax and Examples
The classic manual approach in C is:
#include <stdlib.h>
#include <stdint.h>
size_t size = 1024;
size_t alignment = 16;
void *mem = malloc(size + alignment - 1);
if (mem == NULL) {
/* handle allocation failure */
}
void *ptr = (void *)(((uintptr_t)mem + alignment - 1) & ~(uintptr_t)(alignment - 1));
What this does
malloc(size + alignment - 1)allocates enough extra bytes so there will definitely be some 16-byte-aligned address inside the block.(uintptr_t)memconverts the pointer to an integer type that can safely hold an address.- Adding
alignment - 1ensures rounding goes upward. & ~(alignment - 1)clears the lower bits, producing the next aligned address.
Full example
#include <stdlib.h>
#include <stdint.h>
void example(void) {
void *mem;
void *ptr;
mem = malloc(1024 + 15);
if (mem == NULL) {
return;
}
ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
memset_16aligned(ptr, 0, 1024);
free(mem);
}
Why 15?
For 16-byte alignment:
alignment - 1 = 15- adding 15 and rounding down to the nearest multiple of 16 is equivalent to rounding up to the next multiple of 16
This works because 16 is a power of two.
Step by Step Execution
Consider this example:
#include <stdlib.h>
#include <stdint.h>
void *mem = malloc(32 + 15);
void *ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
Assume malloc returns an address like 1003.
Step 1: Allocate extra space
You ask for 32 + 15 = 47 bytes.
Why extra?
Because somewhere between 1003 and 1003 + 15, there must be an address divisible by 16.
Step 2: Add 15
1003 + 15 = 1018
Step 3: Round down to a multiple of 16
A multiple of 16 near 1018 is 1008.
So:
ptr = 1008
Now 1008 % 16 == 0, so ptr is 16-byte aligned.
Step 4: Use the aligned pointer
memset_16aligned(ptr, 0, 32);
This is safe with respect to alignment.
Step 5: Free the original pointer
free(mem);
You must free mem, not ptr, because only mem came directly from malloc.
Important safety detail
The aligned pointer still points inside the allocated block, and because you allocated extra bytes, there is enough room for the full requested data size starting from ptr.
Real World Use Cases
Aligned memory appears in real systems programming and performance-sensitive code.
Common uses
- SIMD operations: SSE, AVX, and similar instruction sets may require or benefit from aligned data.
- Image and audio processing: buffers are often aligned for vectorized operations.
- Game engines: math libraries and frame buffers may use alignment for speed.
- Networking and device I/O: some hardware interfaces expect specific alignment.
- Custom allocators: memory pools often enforce alignment for objects.
Example scenarios
- A video filter processes 16 bytes at a time using vector instructions.
- A physics engine stores vectors in aligned blocks for fast matrix math.
- A cryptography routine reads data in fixed-size aligned chunks.
Real Codebase Usage
In real projects, developers usually avoid hand-writing alignment logic everywhere. Instead, they wrap it in helper functions or use platform/library APIs.
Common patterns
Guard clauses
Always check allocation results:
mem = malloc(1024 + 15);
if (mem == NULL) {
return;
}
Encapsulating alignment in a helper
#include <stdlib.h>
#include <stdint.h>
void *align_ptr(void *p, size_t alignment) {
return (void *)(((uintptr_t)p + alignment - 1) & ~(uintptr_t)(alignment - 1));
}
This makes call sites cleaner.
Keeping both pointers
A common pattern is to store:
- the original allocation pointer for freeing
- the aligned working pointer for use
Prefer standard APIs when available
In modern code, developers may use:
aligned_allocin C11- platform-specific functions like
posix_memalignor_aligned_malloc
But for interview questions or portable fallback code, manual alignment with malloc is a common pattern.
Validation assumptions
Alignment code often assumes the requested alignment is a power of two. That assumption should be documented or checked if the helper is generic.
Common Mistakes
1. Freeing the adjusted pointer instead of the original one
Broken code:
void *mem = malloc(1024 + 15);
void *ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
free(ptr); /* Wrong */
Why it is wrong:
ptrwas not returned bymalloc- calling
freeon it is undefined behavior
Correct:
free(mem);
2. Not allocating extra space
Broken code:
void *mem = malloc(1024);
void *ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
Why it is risky:
- rounding
memupward may moveptrforward - then there may be fewer than
1024usable bytes left
Correct:
void *mem = malloc(1024 + 15);
3. Using the wrong integer type for pointer arithmetic
Broken code:
void *ptr = (void *)(((unsigned int)mem + 15) & ~15);
Why it is wrong:
unsigned intmay be too small to hold a pointer- this can break on 64-bit systems
Correct:
void *ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
4. Forgetting to check for malloc failure
Broken code:
void *mem = malloc(1024 + 15);
void *ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
If malloc returns NULL, using it is invalid.
Correct:
void *mem = malloc(1024 + 15);
if (mem == NULL) {
return;
}
5. Assuming all alignments work with this exact bit trick
The bit-masking method works cleanly when alignment is a power of two, such as 8, 16, 32, or 64.
If alignment is not a power of two, a different method is needed.
Comparisons
| Approach | Standard | Portable | Easy to Free | Notes |
|---|---|---|---|---|
malloc only | Yes | Yes | Yes | Does not guarantee a chosen alignment like 16 bytes in older C standards |
| Manual over-allocation + adjust pointer | Yes | Yes | Yes, if you keep original pointer | Common interview solution |
aligned_alloc | C11 | Not always available in older environments | Yes | Size must be a multiple of alignment |
posix_memalign | POSIX | No, not pure standard C | Yes | Common on Unix-like systems |
_aligned_malloc | Microsoft-specific | No | Must use _aligned_free | Windows-specific |
Manual alignment vs aligned_alloc
| Feature | Manual malloc method | aligned_alloc |
|---|---|---|
| Works in older standard C | Yes | No |
| Requires extra pointer management | Yes | No |
| Needs custom alignment math | Yes | No |
| Good for interview fundamentals | Yes | Sometimes |
Alignment vs normal allocation
- Normal allocation: enough bytes, but alignment is only whatever
mallocguarantees. - Aligned allocation: enough bytes and a stricter address boundary.
Cheat Sheet
#include <stdlib.h>
#include <stdint.h>
Allocate 1024 bytes aligned to 16
void *mem = malloc(1024 + 15);
if (mem == NULL) {
/* handle error */
}
void *ptr = (void *)(((uintptr_t)mem + 15) & ~(uintptr_t)15);
Use it
memset_16aligned(ptr, 0, 1024);
Free it
free(mem);
Rules
- Allocate
size + alignment - 1 - Align with integer math using
uintptr_t - Alignment should be a power of two
- Free the original
mallocpointer, not the adjusted one - Check for
NULLbefore using the memory
Generic formula
aligned = (void *)(((uintptr_t)raw + alignment - 1) & ~(uintptr_t)(alignment - 1));
C11 option
void *p = aligned_alloc(16, 1024);
free(p);
Note: with aligned_alloc, the size must be a multiple of the alignment.
FAQ
Does malloc already return aligned memory in C?
malloc returns memory suitably aligned for any object type, but that does not always mean it meets a specific requirement like 16-byte alignment in all contexts or older systems.
Why can I not call free(ptr) on the aligned pointer?
Because ptr is not the original pointer returned by malloc. Only the original allocation pointer may be passed to free.
Why do I need to allocate alignment - 1 extra bytes?
That guarantees there is enough room to move forward to the next aligned address without losing usable space from the requested block.
Why is uintptr_t used?
It is an unsigned integer type capable of safely holding a pointer value for address calculations.
Does this bit trick work for any alignment value?
It works when the alignment is a power of two, such as 8, 16, 32, or 64.
Is there a standard C function for aligned allocation?
Yes, aligned_alloc was added in C11. However, older code and interview questions often expect the manual method.
If I use aligned_alloc, do I still need two pointers?
No. aligned_alloc returns the aligned pointer directly, and that same pointer can be passed to free.
What happens if the pointer is not aligned and the function expects alignment?
The result depends on the function and platform. It may crash, behave unpredictably, or just run more slowly.
Mini Project
Description
Build a small C program that allocates a 16-byte-aligned buffer, writes values into it, verifies the alignment, and then frees the memory correctly. This project demonstrates the exact pattern used in interview questions and low-level systems code.
Goal
Create and use a manually aligned 1024-byte buffer using only standard library allocation functions, then release it safely.
Requirements
- Allocate enough memory for a 1024-byte buffer plus extra bytes for alignment.
- Compute a 16-byte-aligned pointer from the original allocation.
- Verify that the computed pointer is divisible by 16.
- Write some bytes into the aligned buffer.
- Free the original pointer, not the adjusted one.
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.