C Dynamic Memory

Dynamic memory is memory that a C program requests while it is running. It is useful when you do not know the needed size until the program runs, such as a list whose length comes from input or a file.

Dynamic memory is managed through pointers. You ask for a block of memory, use the returned pointer, and then release the block when you are done.

Include The Standard Library

The dynamic memory functions are declared in <stdlib.h>. The most common ones are malloc, calloc, realloc, and free.

Function Purpose
malloc Allocates a block of uninitialized memory.
calloc Allocates memory for several items and initializes the bytes to zero.
realloc Changes the size of an existing dynamic memory block.
free Releases memory that was allocated dynamically.

Allocate An Array With malloc

malloc takes the number of bytes to allocate and returns a pointer to the first byte of the block. In C, a void * result from malloc can be assigned to another object pointer type without a cast.

Use sizeof instead of guessing byte counts. A common pattern is count * sizeof *pointer, which stays correct if the pointer type changes later.

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

int main(void)
{
    int count = 4;
    int *scores = malloc(count * sizeof *scores);
    int i;

    if (scores == NULL) {
        printf("Allocation failed\n");
        return 1;
    }

    for (i = 0; i < count; i++) {
        scores[i] = (i + 1) * 10;
    }

    for (i = 0; i < count; i++) {
        printf("Score %d: %d\n", i + 1, scores[i]);
    }

    free(scores);
    scores = NULL;

    return 0;
}

Output:

Score 1: 10
Score 2: 20
Score 3: 30
Score 4: 40

The pointer scores behaves like an array after allocation, so scores[i] accesses each int. The program checks for NULL because allocation can fail. At the end, free(scores) gives the memory back.

Initialize Memory With calloc

calloc takes two arguments: how many items you want and the size of each item. It initializes the allocated bytes to zero, which makes numeric arrays start with zero values.

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

int main(void)
{
    int count = 3;
    int *visits = calloc(count, sizeof *visits);
    int i;

    if (visits == NULL) {
        printf("Allocation failed\n");
        return 1;
    }

    visits[1] = 5;

    for (i = 0; i < count; i++) {
        printf("Day %d: %d\n", i + 1, visits[i]);
    }

    free(visits);

    return 0;
}

Output:

Day 1: 0
Day 2: 5
Day 3: 0

The first and third elements print as 0 because calloc initialized the memory. With malloc, those values would be uninitialized until you assigned them yourself.

Resize Memory With realloc

realloc can grow or shrink a dynamic memory block. It may return the same address or a different address, so store the result in a temporary pointer first. If realloc fails, the original pointer is still valid and must still be freed.

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

int main(void)
{
    int count = 2;
    int *numbers = malloc(count * sizeof *numbers);
    int *larger;
    int i;

    if (numbers == NULL) {
        printf("Allocation failed\n");
        return 1;
    }

    numbers[0] = 7;
    numbers[1] = 14;

    count = 4;
    larger = realloc(numbers, count * sizeof *numbers);
    if (larger == NULL) {
        free(numbers);
        printf("Resize failed\n");
        return 1;
    }

    numbers = larger;
    numbers[2] = 21;
    numbers[3] = 28;

    for (i = 0; i < count; i++) {
        printf("Number %d: %d\n", i + 1, numbers[i]);
    }

    free(numbers);

    return 0;
}

Output:

Number 1: 7
Number 2: 14
Number 3: 21
Number 4: 28

After a successful resize, use the pointer returned by realloc. The new elements are not automatically initialized, so the program assigns values to numbers[2] and numbers[3] before printing them.

Important Dynamic Memory Rules

  • Include <stdlib.h> before using dynamic memory functions.
  • Always check whether allocation returned NULL.
  • Use sizeof to calculate the correct number of bytes.
  • Call free exactly once for each allocated block when you no longer need it.
  • Do not use a pointer after freeing it.
  • Do not read memory that you allocated but have not initialized.

The key idea is that dynamic memory gives your program flexible storage, but you are responsible for checking, initializing, resizing, and freeing it correctly.