Chapter 15: Dynamic Memory Management
Dynamic memory management allows your program to request memory from the Heap at runtime. This is necessary when you don't know the amount of data in advance or when you need data to persist beyond the function that created it.
I. The Heap vs. The Stack
- Stack: Fast, automatic management, small size.
- Heap: Large, manual management, potential for leaks.
II. Allocation Functions (<stdlib.h>)
1. malloc(size_t size)
Allocates a block of memory of the specified size in bytes. The memory contains garbage values (it is not cleared).
int *arr = malloc(5 * sizeof(int)); // Array for 5 integers
if (arr == NULL) { /* Out of memory handle */ }
2. calloc(size_t num, size_t size)
Allocates memory for num elements of size bytes each. The memory is zeroed out.
3. realloc(void *ptr, size_t new_size)
Resizes a previously allocated memory block. It may move the block to a new address if necessary.
III. Freeing Memory (free)
When you are done with heap memory, you must return it to the system.
free(arr);
arr = NULL; // Safety: prevent dangling pointer
IV. Memory Leaks and Overflows
- Memory Leak: Forgetting to call
free. Over time, your program consumes more and more RAM until the system crashes. - Double Free: Calling
freeon the same pointer twice. This causes immediate crashes. - Heap Overflow: Writing beyond the allocated block. This corrupts the heap and lead to security vulnerabilities.
V. Analyzing with Valgrind
Valgrind is the industry standard for detecting memory errors in C programs.
# Run program with leak checking
valgrind --leak-check=full ./my_program
VI. Best Practices
- Check for NULL: Every call to
malloccan fail. Always check if the returned pointer isNULL. - One Malloc, One Free: Aim for a clear design where it's obvious who "owns" the memory and is responsible for freeing it.
- Use Calloc by Default: Unless you are in a performance-critical tight loop,
callocis safer because it prevents reading garbage data.