calloc()
calloc() (short for "clear allocation") is a second way to allocate heap memory in C, also declared in <stdlib.h>. It does the same fundamental job as malloc() — reserving a block of heap memory — but with two important differences: it takes the size as two parameters instead of one, and it guarantees the memory it gives you is zero-initialized.void *calloc(size_t count, size_t size);
Why Two Parameters?
malloc() does, calloc() asks for a count of elements and the size of each one. It then allocates count * size bytes total. This mirrors how you usually think about allocating an array — "I want room for 10 ints" — and, as covered below, it lets the implementation check that multiplication for overflow on your behalf.int *arr = calloc(10, sizeof(int)); // room for 10 ints, all zeroed
The Key Difference: Zero-Initialization
malloc(), which leaves the allocated memory containing whatever garbage bytes happened to be there, calloc() guarantees every byte of the returned block is set to zero before you get it.#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 5;
int *counts = calloc(n, sizeof(int));
if (counts == NULL) {
fprintf(stderr, "Allocation failed\n");
return 1;
}
for (int i = 0; i < n; i++) {
printf("%d\n", counts[i]); // guaranteed to print 0, five times
}
free(counts);
return 0;
}0 0 0 0 0
calloc() vs malloc() + memset()
malloc() with memset():int *a = malloc(n * sizeof(int));
if (a != NULL) {
memset(a, 0, n * sizeof(int));
}
// vs. the equivalent, more direct calloc call:
int *b = calloc(n, sizeof(int));calloc() version is not just shorter — many C library implementations can satisfy a calloc() request more efficiently than a manual malloc() + memset(). For instance, memory freshly obtained from the operating system is often already zeroed by the OS, and a good calloc() implementation can detect that and skip redundantly zeroing it again — an optimization that a hand-rolled malloc()+memset() combination cannot take advantage of.Overflow Safety
calloc() when allocating arrays. If you compute a total byte count yourself for malloc(), the multiplication can silently overflow if count and size are both attacker- or user-controlled and large enough:size_t count = huge_user_supplied_value; size_t size = sizeof(int); // If count * size overflows size_t, this wraps around to a SMALL number. // malloc() then "succeeds" with a block far smaller than you intended! int *arr = malloc(count * size);
count elements. Writing to it past the real (small) size is a heap buffer overflow — a serious security vulnerability, not just a logic bug.calloc(count, size) is required by the C standard to check this multiplication internally and return NULL if count * size would overflow, instead of silently wrapping around. That safety check is the whole reason its signature takes two separate parameters rather than one pre-multiplied size.malloc() vs calloc()
malloc(size) | calloc(count, size) | |
|---|---|---|
Parameters | One: total bytes | Two: element count and element size |
Initializes memory? | No -- contents are garbage | Yes -- always zeroed |
Overflow protection | None -- you must check yourself | Built in -- fails safely on overflow |
Best for | Data you will fully overwrite immediately | Arrays, counters, or anything that should start at zero |
int is 0) and for pointers (an all-zero pointer is a NULL pointer on virtually all platforms). It is not a substitute for properly initializing structs with meaningful default values, or floating-point data whose meaningful default isn't zero.calloc(count, size)allocatescount * sizebytes and guarantees they are zero-initializedPrefer it over
malloc()+memset()for both clarity and potential performance benefitsIt checks the
count * sizemultiplication for overflow internally, unlike a manualmalloc(count * size)callLike
malloc(), always check the return value forNULLbefore using itEvery successful
calloc()still needs exactly one matchingfree()