calloc, realloc & free
Allocating heap memory, resizing it, and cleaning it up without leaks
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
callocto 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.
calloc but never call free?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.