student@ubuntu:~$
pointers-memory Lesson 8 10 min read

calloc, realloc & free

Allocating heap memory, resizing it, and cleaning it up without leaks

Reading: Hanly & Koffman: §13.1–13.2 (pp. 706–716)

Quick check before you start: Can you explain the difference between stack and heap lifetime? If yes, skip to calloc: The Preferred Allocator. If not, review Lesson 7a.

Practice this topic: Dynamic Memory skill drill

After this lesson, you will be able to:

  • Use calloc to allocate zeroed heap memory
  • Check for allocation failure with NULL
  • Resize allocations safely with realloc
  • Identify memory leaks, use-after-free, and double-free bugs
  • Free every allocation exactly once

calloc: The Preferred Allocator

In this course, we use calloc instead of malloc. Both allocate heap memory, but calloc zeros the bytes. That means your memory starts clean — no garbage values.

#include <stdlib.h>

int *arr = calloc(10, sizeof(int));  // 10 ints, all zeroed

The two arguments are: count and size of each element. This is easier to read than malloc(10 * sizeof(int)) and avoids integer overflow bugs.

Always Check for NULL

calloc returns NULL if the system cannot allocate the memory. If you dereference NULL, your program crashes with a segfault.

int *arr = calloc(10, sizeof(int));
if (arr == NULL) {
    fprintf(stderr, "Error: calloc failed\n");
    exit(EXIT_FAILURE);
}

Make this a habit. Every calloc call gets a NULL check on the next line.

Memory Leaks

A memory leak happens when you lose all pointers to a heap allocation without freeing it.

void leak(void) {
    int *p = calloc(100, sizeof(int));
    // p goes out of scope — the 400 bytes are lost forever
}

In Java, the garbage collector would reclaim that memory. In C, it stays allocated until the program exits. In a long-running program, leaks accumulate and eventually exhaust memory.

Use-After-Free

Accessing memory after you have freed it is undefined behavior. The memory might be reused for something else, so you could read garbage or corrupt another variable.

int *p = calloc(1, sizeof(int));
*p = 42;
free(p);
printf("%d\n", *p);  // BUG: use-after-free

After free(p), set the pointer to NULL:

free(p);
p = NULL;

Now if you accidentally dereference it, you get a clean crash instead of silent corruption.

Double Free

Calling free on the same pointer twice corrupts the heap’s internal bookkeeping. This can crash your program or cause exploitable security vulnerabilities.

free(p);
free(p);  // BUG: double free

Setting the pointer to NULL after freeing also prevents this, because free(NULL) is safe and does nothing.

The realloc Pattern

realloc resizes an existing allocation. The safe pattern uses a temporary pointer:

int *temp = realloc(arr, new_count * sizeof(int));
if (temp == NULL) {
    fprintf(stderr, "Error: realloc failed\n");
    free(arr);  // original is still valid
    exit(EXIT_FAILURE);
}
arr = temp;

Never write arr = realloc(arr, ...) directly. If realloc fails, it returns NULL and you lose your only pointer to the original memory — instant leak.


Check Your Understanding
What happens if you allocate memory with calloc but never call free?
AThe compiler catches the error
BThe memory leaks — it stays allocated until the program exits
CThe OS automatically frees it when the function returns
DC's garbage collector reclaims it
Answer: B. C has no garbage collector. Heap memory allocated with calloc persists until you explicitly call free or the entire program terminates. The OS reclaims everything when the process ends, but during execution, unfree'd memory is a leak.

What Comes Next

You know how to allocate and free memory. But how do you find the bugs you missed? Next, you will learn to use Valgrind to detect leaks, invalid reads, and use-after-free errors automatically.

Next: Debugging Memory with Valgrind