C - memory management in C
1. Memory in a C Program
When a C program runs, memory is typically divided into:
Memory Region | Purpose | Managed By |
---|---|---|
Code/Text | Stores program instructions | Compiler/OS |
Global/Static | Stores global and static variables | Compiler/OS |
Stack | Stores function call frames, local variables | Automatically managed (LIFO) |
Heap | Stores dynamically allocated memory | You (via malloc , free , etc.) |
2. Static vs Dynamic Memory
-
Static: Known at compile time (global variables, static variables, fixed-size arrays).
-
Automatic: Created on the stack, freed when function exits.
-
Dynamic: Allocated at runtime on the heap, must be manually freed.
3. Dynamic Memory Allocation Functions
From <stdlib.h>
:
Function | Purpose | Notes |
---|---|---|
malloc(size) |
Allocates size bytes |
Contents uninitialized |
calloc(n, size) |
Allocates n * size bytes |
Initializes to zero |
realloc(ptr, new_size) |
Changes size of allocated memory | May move memory |
free(ptr) |
Frees allocated memory | ptr must be from malloc , calloc , or realloc |
Example:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = malloc(5 * sizeof(int)); // allocate for 5 ints
if (!arr) {
printf("Memory allocation failed\n");
return 1;
}
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
arr = realloc(arr, 10 * sizeof(int)); // resize
if (!arr) {
printf("Reallocation failed\n");
return 1;
}
free(arr); // release memory
return 0;
}
4. malloc
vs calloc
-
malloc
: Faster, memory not initialized -
calloc
: Slower, memory is initialized to zero
Example:
int *p = malloc(5 * sizeof(int)); // garbage values
int *q = calloc(5, sizeof(int)); // all values are 0
5. Common Memory Issues in C
-
Memory leaks — forgetting to
free()
allocated memory -
Dangling pointers — using a pointer after freeing it
-
Double free — freeing the same pointer twice
-
Buffer overflow — writing beyond allocated size
-
Uninitialized memory usage — reading before assigning
6. Best Practices
-
Always check if
malloc
/calloc
/realloc
returnsNULL
-
free()
everything you allocate before program exits -
Set pointers to
NULL
afterfree()
to avoid dangling pointers -
Use
sizeof(*ptr)
instead ofsizeof(type)
to avoid type mismatches -
Avoid memory allocation inside tight loops unless necessary
7. Visual Diagram
Imagine this code:
int x = 10; // stack
int *p = malloc(sizeof(int)); // heap
*p = 20;
Memory layout:
Stack:
[ x=10 ] [ p = 0x6000 ]
Heap:
0x6000 -> [ 20 ]
8. Detecting Memory Problems
Tools like:
-
Valgrind (Linux/Mac) — detects leaks and invalid memory access
-
AddressSanitizer (via
-fsanitize=address
in GCC/Clang)
Do you want me to make that?