0Pricing
C Academy · Lesson

Alignment and Splitting

Make blocks usable and tidy.

Alignment and Splitting is a free C Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Alignment Matters

Every type has an alignment requirement: its address must be a multiple of some power of two. A double typically needs 8-byte alignment.

Because malloc does not know what you will store, it must return pointers aligned for the strictest type, usually 16 bytes on 64-bit systems.

#include <stdalign.h>
/* the strictest fundamental alignment */
size_t strict = alignof(max_align_t);   /* often 16 */

The align_up Trick

Rounding a size up to the next multiple of a power-of-two alignment is a classic bit trick: add a - 1, then mask off the low bits.

This works only when a is a power of two, which all real alignments are.

static size_t align_up(size_t n, size_t a) {
    return (n + a - 1) & ~(a - 1);
}
/* align_up(13, 8) == 16, align_up(16, 8) == 16 */

Proving the Math Runs

Let's verify align_up with a runnable program. It rounds several sizes up to 8- and 16-byte boundaries and prints the results.

#include <stdio.h>
#include <stddef.h>

static size_t align_up(size_t n, size_t a) {
    return (n + a - 1) & ~(a - 1);
}

int main(void) {
    printf("%zu\n", align_up(13, 8));   /* 16 */
    printf("%zu\n", align_up(16, 8));   /* 16 */
    printf("%zu\n", align_up(1, 16));   /* 16 */
    printf("%zu\n", align_up(33, 16));  /* 48 */
    return 0;
}

Aligning Requested Sizes

Inside the allocator, the first step of every request is to round the requested size up to the alignment. This guarantees the next block also starts aligned.

The padding bytes are internal fragmentation, the price of universal alignment.

#define ALIGN 16
void *my_alloc(size_t size) {
    size = align_up(size, ALIGN);
    /* now find a block of this aligned size */
    /* ... */
    return NULL;
}

The Problem with Whole-Block Reuse

In the previous lesson we returned an entire free block even for tiny requests. A 4000-byte free block handed out for a 16-byte request wastes the rest.

Splitting cuts the block into the part we use and a remainder that stays free.

Splitting a Block

If a chosen block is much larger than needed, we place a new header at the end of the requested region. The leftover becomes a smaller free block in the list.

We only split when the remainder is big enough to hold a header plus some payload, or the fragment is useless.

void split(block_t *b, size_t size) {
    size_t rem = b->size - size;
    if (rem < sizeof(block_t) + ALIGN) return; /* too small */
    block_t *nb = (block_t *)((char *)(b + 1) + size);
    nb->size = rem - sizeof(block_t);
    nb->free = 1;
    nb->next = b->next;
    b->size = size;
    b->next = nb;
}

Allocate, Align, Split

The full allocation path now aligns the size, finds a fit, splits off any large remainder, and marks the block used.

This keeps blocks tightly sized and leaves usable free space behind.

void *my_alloc(size_t size) {
    size = align_up(size, ALIGN);
    block_t *b = first_fit(size);
    if (!b) return NULL;
    split(b, size);
    b->free = 0;
    return (void *)(b + 1);
}

Keeping the Pool Itself Aligned

For correctness the pool's starting address and the header size should also respect alignment, so every payload lands on a boundary.

Using alignas on the static buffer guarantees the whole scheme starts aligned.

#include <stdalign.h>
alignas(16) static unsigned char pool[4096];
/* pool now begins on a 16-byte boundary */

A Runnable Aligned Allocation

This program allocates from an aligned pool and prints the returned address modulo 16, showing it is always zero, i.e. properly aligned.

#include <stdio.h>
#include <stddef.h>
#include <stdalign.h>

static size_t align_up(size_t n, size_t a){ return (n+a-1)&~(a-1); }
alignas(16) static unsigned char pool[1024];
static size_t off = 0;

void *alloc16(size_t s){ off=align_up(off,16); if(off+s>sizeof(pool)) return NULL; void*p=&pool[off]; off+=s; return p; }

int main(void){
    void *a = alloc16(1);
    void *b = alloc16(20);
    printf("a %% 16 = %lu\n", (unsigned long)((size_t)a % 16));
    printf("b %% 16 = %lu\n", (unsigned long)((size_t)b % 16));
    return 0;
}

Splitting vs Coalescing

Splitting and coalescing are opposites that balance each other. Allocation splits big blocks down; freeing coalesces small blocks back up.

Together they let the same pool serve a changing mix of request sizes without leaking space or fragmenting permanently.

From Toy to Real Allocator

You now have all four pillars: a memory source, aligned headers, free-list reuse with coalescing, and splitting. Real allocators add size-class bins, thread caches, and OS integration for speed and scale.

But the core ideas you built here power every malloc implementation.

Quick Check

Consider why blocks are split during allocation.

Recap

Alignment rounds sizes up with the bit trick (n + a - 1) & ~(a - 1) so every payload suits any type. Splitting carves oversized free blocks into a used part and a free remainder, while coalescing reverses it on free.

These four pillars together form a complete, correct memory allocator.

Frequently asked questions

Is the “Alignment and Splitting” lesson free?

Yes — the full text of “Alignment and Splitting” is free to read here on the web, and the C Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO.

What will I learn in “Alignment and Splitting”?

Make blocks usable and tidy. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C Academy?

No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Alignment and Splitting” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C Academy lesson?

Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. How malloc Works
  2. A Simple Bump Allocator
  3. Free Lists and Reuse
  4. Alignment and Splitting
← Back to C Academy