Bytebook Compiler

Pointers & Memory

Dynamic Memory Allocation

Ask for memory at run time with malloc, calloc and realloc, give it back with free, and avoid leaks and dangling pointers.

5 min read4 runnable examples4-question quiz

So far every array had a size fixed when you wrote the program. But often you only learn the size while the program runs — how many students in this class? How many lines in this file? Dynamic memory allocation asks the operating system for memory at run time, from a region called the heap.

Stack vs heap

Stack Heap
Used for local variables, function calls memory you request with malloc
Size small (often 1–8 MB) large (most of RAM)
Freed automatically when the function returns only when you call free
Speed very fast slower to allocate

malloc

malloc(bytes) returns a pointer to a block of uninitialised memory, or NULL if it fails. All four functions live in stdlib.h.

C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n;
    printf("Number of students: ");
    scanf("%d", &n);

    int *marks = malloc(n * sizeof(int));     // room for n ints
    if (marks == NULL) {
        printf("Out of memory!\n");
        return 1;
    }

    printf("Enter %d marks: ", n);
    for (int i = 0; i < n; i++) scanf("%d", &marks[i]);   // use it like an array

    int total = 0;
    for (int i = 0; i < n; i++) total += marks[i];
    printf("Average: %.1f\n", (double)total / n);

    free(marks);          // give the memory back
    marks = NULL;         // avoid a dangling pointer
    return 0;
}
Output
Number of students: 5
Enter 5 marks: 80 92 67 74 88
Average: 80.2
Sample input is includedTry it Yourself

calloc

calloc(count, size) allocates count × size bytes and sets them all to zero:

C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *freq = calloc(10, sizeof(int));   // ten zeros
    int digits[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    for (int i = 0; i < 11; i++) freq[digits[i]]++;
    for (int d = 0; d < 10; d++)
        if (freq[d]) printf("digit %d appears %d time(s)\n", d, freq[d]);
    free(freq);
    return 0;
}
Output
digit 1 appears 2 time(s)
digit 2 appears 1 time(s)
digit 3 appears 2 time(s)
digit 4 appears 1 time(s)
digit 5 appears 3 time(s)
digit 6 appears 1 time(s)
digit 9 appears 1 time(s)

realloc

realloc(ptr, newBytes) resizes a block. It may move the data to a new address, so always use the pointer it returns. This is how growable arrays (like C++'s vector or Python's list) work underneath:

C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int capacity = 2, size = 0;
    int *a = malloc(capacity * sizeof(int));
    for (int value = 1; value <= 9; value++) {
        if (size == capacity) {
            capacity *= 2;                                   // double when full
            int *bigger = realloc(a, capacity * sizeof(int));
            if (!bigger) { free(a); return 1; }
            a = bigger;
            printf("grew to capacity %d\n", capacity);
        }
        a[size++] = value * value;
    }
    for (int i = 0; i < size; i++) printf("%d ", a[i]);
    printf("\n");
    free(a);
    return 0;
}
Output
grew to capacity 4
grew to capacity 8
grew to capacity 16
1 4 9 16 25 36 49 64 81

malloc vs calloc

malloc(n * size) calloc(n, size)
one argument: total bytes two arguments: count and element size
memory contains garbage memory is zeroed
slightly faster safe default when you need zeros

Dynamic 2D arrays

Allocate an array of row pointers, then each row:

C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int rows = 3, cols = 4;
    int **grid = malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        grid[i] = malloc(cols * sizeof(int));
        for (int j = 0; j < cols; j++) grid[i][j] = i * cols + j;
    }
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) printf("%3d", grid[i][j]);
        printf("\n");
    }
    for (int i = 0; i < rows; i++) free(grid[i]);   // free rows first
    free(grid);                                     // then the row array
    return 0;
}
Output
  0  1  2  3
  4  5  6  7
  8  9 10 11

Memory leaks

A memory leak happens when you lose the last pointer to a block without freeing it. The memory stays reserved until the program ends. In long-running programs (servers, games) leaks slowly eat all RAM.

C
void leaky(void) {
    int *p = malloc(100 * sizeof(int));
    // ... use p ...
    // forgot free(p): when the function returns, p disappears but the block stays
}

Test yourself

4 questions · pick an answer to check it instantly

  1. 1

    What does malloc return when it cannot allocate memory?

  2. 2

    Which function returns zero-filled memory?

  3. 3

    After free(p);, what is p?

  4. 4

    Why must you use the return value of realloc?