Dynamic Memory Allocation in C: Mastering malloc, calloc, realloc, and free
Before diving into dynamic memory allocation in C, it’s essential to understand how memory is managed in the language.
How Memory Management Works in C
When you declare a variable with a primitive type, the compiler allocates space for it on the stack automatically. For example, a float typically occupies 4 bytes (platform‑dependent). You can confirm this with the sizeof operator:
#include <stdio.h>
int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0; }
The output will be:
The size of float is 4 bytes
An array of a specified size is also allocated contiguously on the stack, with each element occupying the size of its type:
#include <stdio.h>
int main() { float arr[10]; printf("The size of the float array with 10 elements is %d", sizeof(arr)); return 0; }
The result is:
The size of the float array with 10 elements is 40
While stack allocation is automatic, many programs require memory whose size is not known until runtime. This need is addressed by dynamic memory allocation, which uses the heap instead of the stack.
Dynamic Memory Allocation in C
Dynamic allocation involves manually requesting and releasing memory as needed, with pointers tracking the allocated blocks on the heap. The C standard library provides several functions for this purpose:
- malloc() – Allocates a contiguous block of bytes and returns a pointer to its first byte.
- calloc() – Allocates an array of elements, initializes all bytes to zero, and returns a pointer to the first element.
- realloc() – Resizes a previously allocated block, preserving its contents.
- free() – Releases a previously allocated block back to the heap.
Let’s explore each function in detail.
malloc() Function
The malloc() function stands for “memory allocation.” It reserves a block of memory of a specified size and returns a pointer to it. The pointer is typically cast to the desired type:
ptr = (cast_type *) malloc(byte_size);
Example:
#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* 15 integers */
if (ptr != NULL) {
*(ptr + 5) = 480; /* sixth element */
printf("Value of the 6th integer is %d", *(ptr + 5));
}
}
Output:
Value of the 6th integer is 480
Key points:
- Use
sizeof(*ptr)to make the code robust against type changes. - Check for a
NULLreturn value to detect allocation failure. - Allocated memory is contiguous; treat it as an array and use pointer arithmetic.
Dynamic allocation is not limited to primitive types; it works with structures, character arrays, and more.
free() Function
Memory allocated with malloc(), calloc(), or realloc() must be released explicitly to avoid leaks. The free() function performs this task:
#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
*(ptr + 2) = 50;
printf("Value of the 2nd integer is %d", *(ptr + 2));
}
free(ptr);
}
Output:
Value of the 2nd integer is 50
calloc() Function
calloc() allocates multiple blocks of equal size and initializes every byte to zero, making it ideal for arrays and structures that require zeroed memory:
ptr = (cast_type *) calloc(n, size);
Example – summing an arithmetic sequence:
#include <stdio.h>
int main() {
int i, *ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
for (i = 0; i < 10; ++i) {
*(ptr + i) = i;
sum += *(ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
Result:
Sum = 45
calloc() vs. malloc()
Key differences:
- Initialization:
calloc()zeroes memory;malloc()leaves it uninitialized (garbage). - Usage:
calloc()is preferable for arrays or structures that need zeroed values;malloc()is simpler when no initialization is required. - Performance: Both perform similarly, but
calloc()may be slightly slower due to zeroing.
realloc() Function
The realloc() function changes the size of an existing allocation while preserving its contents:
ptr = realloc(ptr, newsize);
Example – extending a string buffer:
#include <stdio.h>
int main () {
char *ptr = malloc(10);
strcpy(ptr, "Programming");
ptr = realloc(ptr, 20); // enlarge
strcat(ptr, " In 'C'");
printf("%s, Address = %u", ptr, ptr);
free(ptr);
return 0;
}
If reallocation fails, realloc() returns NULL and the original block remains valid.
Dynamic Arrays
Dynamic arrays allow the number of elements to grow during execution, a common pattern in algorithms and data structures:
#include <stdio.h>
int main() {
int *arr_dynamic = NULL;
int elements = 2, i;
arr_dynamic = calloc(elements, sizeof(int));
for (i = 0; i < elements; i++) arr_dynamic[i] = i;
for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
elements = 4;
arr_dynamic = realloc(arr_dynamic, elements * sizeof(int));
printf("After realloc\n");
for (i = 2; i < elements; i++) arr_dynamic[i] = i;
for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
free(arr_dynamic);
}
Result:
arr_dynamic[0]=0 arr_dynamic[1]=1 After realloc arr_dynamic[0]=0 arr_dynamic[1]=1 arr_dynamic[2]=2 arr_dynamic[3]=3
Summary
- Dynamic memory lets you allocate and deallocate heap space at runtime.
- Use
malloc()for single blocks,calloc()for zero‑initialized arrays. - Always check for
NULLto detect allocation failures. - Release memory with
free()to avoid leaks. - Resize allocations with
realloc()when more space is needed. - Dynamic arrays are a powerful pattern for flexible data structures.
C Language
- Mastering C# Using Statements: Imports, Aliases, and Static Directives
- Mastering C++ Functions: From Basics to Advanced Usage
- Mastering C Functions: User-Defined and Standard Library Basics
- Dynamic Memory Allocation in C: Mastering malloc, calloc, realloc, and free
- Master C++ Dynamic Array Allocation: A Practical Guide with Code Examples
- malloc vs calloc: Key Differences Explained with Practical Examples
- calloc() in C: Zero‑Initialized Memory Allocation and a Practical Example
- Java Stack vs. Heap: A Practical Memory Allocation Guide
- Mastering C++ Dynamic Memory: Stack vs. Heap Explained
- Java 10 Enhancements: Allocate Heap on NV‑DIMM with -XX:AllocateHeapAt