Skip to content
AgileLogics
6 min read

Dynamic Memory Allocation

Prerequisites: Pointers deep dive

Arrays declared with a fixed size (int nums[5]) live on the stack and must have a size known at compile time (or, in C99+, at least at the point of declaration). malloc instead requests memory from the heap at runtime, sized however the program needs — and that memory must be explicitly released with free when done.

Syntax

#include <stdlib.h>

int *nums = malloc(5 * sizeof(int));
if (nums == NULL) {
    // allocation failed — handle it, don't just proceed
}

nums[0] = 10;
free(nums);
nums = NULL; // avoid an accidental later use

Example

int n = 5;
int *nums = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
    nums[i] = i * i;
}
for (int i = 0; i < n; i++) {
    printf("%d\n", nums[i]);
}
free(nums);

Expected output

0
1
4
9
16

calloc(n, size) allocates and zero-initializes; realloc(ptr, newSize) resizes a previous allocation, possibly moving it (always reassign its result — it may not equal the original pointer).

Common mistakes

  • Forgetting to check malloc's return value for NULL before using it — a failed allocation returns NULL, and dereferencing that crashes.
  • Calling free on the same pointer twice ("double free") — this is undefined behavior, and often crashes later, unpredictably.
  • Using memory after freeing it ("use-after-free") — a serious class of bug that even shows up as a real security vulnerability class in production software.

Practice

Allocate an array of 10 ints with malloc, fill it with the squares of 0–9, print them, then free it.

Show solution
int *squares = malloc(10 * sizeof(int));
for (int i = 0; i < 10; i++) {
    squares[i] = i * i;
    printf("%d\n", squares[i]);
}
free(squares);