In C, memory is typically allocated in two primary areas:
- Stack: Used for local variables and function calls. Memory is managed automatically by the compiler.
- Heap: A large pool of free memory managed manually by the programmer using special functions. This allows allocating memory whose size is not known until the program is running (runtime).
Dynamic Memory Allocation refers to managing memory from the heap. This is crucial for creating resizable data structures like linked lists and for handling user input of unknown size.
1. Heap Management Functions (<stdlib.h>)
The standard library <stdlib.h> contains the four functions necessary for heap management. All these functions return a pointer of type void * (a generic pointer).
A. Allocation (malloc)
The malloc() (memory allocation) function allocates a block of memory of the specified size (in bytes) and returns a pointer to the beginning of the block. The memory contents are uninitialized (contain garbage values).
Syntax: ptr = (cast_type *) malloc(size_in_bytes);
We use the sizeof operator to calculate the correct number of bytes needed for a specific number of elements.
#include <stdlib.h> // Required for malloc and free
int n = 5;
// Allocate memory for 5 integers (5 * 4 bytes = 20 bytes)
int *data_ptr = (int *)malloc(n * sizeof(int));
if (data_ptr == NULL) {
// Check if allocation failed
printf("Memory allocation failed!\n");
}
B. Allocation and Initialization (calloc)
The calloc() (contiguous allocation) function allocates memory and initializes all allocated bytes to zero. It takes the number of elements and the size of each element separately.
Syntax: ptr = (cast_type *) calloc(num_elements, element_size);
// Allocate memory for 5 integers, all initialized to 0
int *zero_ptr = (int *)calloc(n, sizeof(int));
2. Deallocation (free)
Deallocation is the manual return of heap memory back to the system. This must be done when the memory is no longer needed. Failing to use free() causes a memory leak.
// data_ptr now points to memory that is free for reuse
free(data_ptr);
// Good practice: set the pointer to NULL after freeing
data_ptr = NULL;
3. Reallocation (realloc)
The realloc() (re-allocation) function changes the size of the memory block pointed to by a given pointer. It returns a new pointer, which may or may not be the same as the original, depending on whether the original block could be resized in place.
Syntax: new_ptr = (cast_type *) realloc(old_ptr, new_size_in_bytes);
// Resize the memory block originally pointed to by data_ptr to hold 10 integers
int *new_data_ptr = (int *)realloc(data_ptr, 10 * sizeof(int));
4. Memory Leaks and Dangling Pointers
- Memory Leak: Occurs when allocated memory is no longer reachable by the program (you lose the pointer) but has not been returned to the heap via
free(). The OS cannot reuse this memory, leading to resource exhaustion over time. - Dangling Pointer: Occurs when a pointer still holds the address of memory that has already been deallocated using
free(). Dereferencing a dangling pointer leads to undefined behavior (crashes or corrupt data).
