Memory Management in C
Master the two memory worlds: Stack vs Heap, and learn to manage memory like a pro.
๐ค Why Do We Need to Understand Memory?
๐ก The "Your Room" Analogy
Imagine your program is like your bedroom:
- You have a small desk (stack) where you keep things you need right now โ your notebook, pen, calculator. It's organized, easy to reach, but limited space.
- You have a big closet (heap) where you store everything else โ clothes, old books, boxes. It's larger but you have to manually organize it.
In C, you get to choose where your data lives. Making the right choice keeps your program fast and efficient!
๐ฝ๏ธ Stack vs Heap: The Real-World Analogy
๐ The "Stack of Plates" (Stack Memory)
๐ฝ๏ธ STACK OF PLATES
Think of a cafeteria plate dispenser:
โโโโโโโ โ TOP (most recent)
โ ๐ฝ๏ธ โ Plate 3 (last function call)
โโโโโโโค
โ ๐ฝ๏ธ โ Plate 2 (middle function)
โโโโโโโค
โ ๐ฝ๏ธ โ Plate 1 (main function)
โโโโโโโค
โ โ
โโโโโโโ โ BOTTOM
๐ KEY CHARACTERISTICS:
โข Last In, First Out (LIFO)
โข Automatic: Plates are pushed on and popped off
โข Limited: Only so many plates fit
โข Fast: Just grab from the top!
In C: Local variables and function calls live here
๐งธ The "Heap of Toys" (Heap Memory)
๐งธ HEAP OF TOYS
Think of a toy box where toys are scattered:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ ๐ ๐ค โ
โ โ
โ ๐งฉ ๐ฎ โ
โ โ
โ ๐ฏ โ
โ ๐ฒ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ KEY CHARACTERISTICS:
โข No order: Toys are placed anywhere
โข Manual: YOU must pick up and put away
โข Large: Much more space than the plate stack
โข Slower: Have to search for space
In C: Dynamic allocation with malloc/calloc lives here
๐ Stack vs Heap Comparison
| Feature | Stack ๐ฝ๏ธ | Heap ๐งธ |
|---|---|---|
| Organization | Neat stack (LIFO) | Scattered blocks |
| Allocation | Automatic | Manual (you control it) |
| Deallocation | Automatic when function ends | Manual (free()) |
| Size | Limited (usually 1-8 MB) | Larger (GB available) |
| Speed | Very fast | Slower |
| Scope | Local to function | Global access |
| Fragmentation | Never | Can happen |
๐พ C Program Memory Layout
๐๏ธ How Your Program Uses Memory
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ HIGH MEMORY ADDRESS โ
โ (0xFFFFFFFF on 32-bit) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Stack starts here
โ โ โ GROWS DOWN
โ STACK ๐ฝ๏ธ โ โ โ โ
โ Local variables, function calls โ
โ Grows DOWNWARD (toward lower addresses)โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โ๏ธ GAP โ๏ธ โ
โ Free space for heap to grow โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ โ GROWS UP
โ HEAP ๐งธ โ โ โ โ
โ malloc(), calloc(), realloc() โ
โ Grows UPWARD (toward higher addresses)โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ Heap starts here
โ โ
โ BSS ๐ โ
โ Uninitialized global/static variablesโ
โ (set to 0 by default) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ DATA SEGMENT ๐ โ
โ Initialized global/static variables โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ TEXT/CODE SEGMENT ๐ โ
โ Your program's instructions โ
โ (read-only, executable) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ LOW MEMORY ADDRESS โ
โ (0x00000000) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ก MEMORY MAP ANATOMY:
โข Text/Code: Where your compiled code lives
โข Data: Global variables with values you set
โข BSS: Global variables you declared but didn't initialize
โข Heap: Dynamic memory you request (malloc)
โข Stack: Function calls and local variables
๐ Memory Regions Quick Reference
| Region | What Lives Here | Who Manages It |
|---|---|---|
| Text/Code | Program instructions, compiled code | OS (read-only) |
| Data | Initialized global/static variables | Compiler |
| BSS | Uninitialized global/static variables | OS (zeroed) |
| Heap | Dynamically allocated memory | You! (malloc/free) |
| Stack | Local variables, function parameters | Automatic |
๐ป Stack vs Heap in Code
๐ Visual: What Goes Where
Code Example:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int global = 10; // DATA segment โ
โ int uninit; // BSS segment (starts as 0) โ
โ โ
โ void myFunction() { โ
โ int local = 5; // STACK ๐ฝ๏ธ โ
โ int arr[10]; // STACK ๐ฝ๏ธ โ
โ โ
โ int *ptr = malloc(100); // HEAP ๐งธ โ
โ // ptr (the variable) is on STACK โ
โ // but points to memory on HEAP โ
โ โ
โ free(ptr); // Give HEAP memory back โ
โ } โ
โ โ
โ int main() { โ
โ myFunction(); โ
โ return 0; โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
MEMORY DURING EXECUTION:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ STACK (top) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ main()'s stack frame โ โ
โ โ (return address, etc.) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ myFunction()'s stack frame โ โ
โ โ local = 5 โ โ
โ โ arr[10] = {?,?,?,?,?,?,?,?,?,?} โ โ
โ โ ptr = 0x2000 (address on heap) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ HEAP: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Address 0x2000: 100 bytes allocated โ โ
โ โ for ptr โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ DATA: global = 10 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ BSS: uninit = 0 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
stack_vs_heap.c
#include <stdio.h>
#include <stdlib.h>
void demonstrateStack() {
// These live on the STACK
int localVar = 10; // Stack variable
int localArray[100]; // Stack array
printf("Stack variable: %d\n", localVar);
printf("Stack array size: %zu bytes\n", sizeof(localArray));
// All stack variables are automatically freed
// when this function returns!
}
void demonstrateHeap() {
// This lives on the HEAP
int *heapArray = (int*)malloc(100 * sizeof(int));
if (heapArray == NULL) {
printf("Memory allocation failed!\n");
return;
}
printf("Heap memory allocated!\n");
// Use the memory
for (int i = 0; i < 100; i++) {
heapArray[i] = i * 10;
}
printf("First value: %d\n", heapArray[0]);
printf("Last value: %d\n", heapArray[99]);
// MUST manually free heap memory!
free(heapArray);
printf("Heap memory freed!\n");
}
int main() {
printf("=== Stack Demo ===\n");
demonstrateStack();
printf("\n=== Heap Demo ===\n");
demonstrateHeap();
return 0;
}
๐ Dynamic Memory Functions Explained Simply
๐ก The "Library Book" Analogy
Think of heap memory like borrowing books from a library:
๐ malloc() - "Asking for Memory"
Like asking the librarian for books
๐ MALLOC - Memory ALLOCation
You: "Can I have 100 bytes of memory?"
OS (Operating System): "Sure, here you go!"
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = malloc(100); โ
โ โ
โ Before: โ
โ ptr โ ??? (uninitialized) โ
โ โ
โ After: โ
โ ptr โ [???][???][???]... (100 bytes) โ
โ โ โ
โ Memory contains GARBAGE values โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ malloc gives you RAW memory - it could contain
any random values! Always initialize before use.
โจ calloc() - "Asking for Clean Memory"
Like asking for new, clean books
โจ CALLOC - Contiguous ALLOCation with Zero
You: "Can I have 10 integers, all set to 0?"
OS: "Sure, here are 10 clean, zeroed integers!"
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = calloc(10, sizeof(int)); โ
โ โ
โ Before: โ
โ ptr โ ??? โ
โ โ
โ After: โ
โ ptr โ [0][0][0][0][0][0][0][0][0][0] โ
โ โ โ
โ Memory is ZEROED/CLEAN! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Use calloc when you need memory initialized to 0
(e.g., for arrays, counters)
๐ realloc() - "Resizing Your Memory"
Like asking for a bigger table at a restaurant
๐ REALLOC - REsize ALLOCated memory
Scenario: You asked for 5 integers, but now need 10!
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = malloc(5 * sizeof(int)); โ
โ // ptr โ [1][2][3][4][5] โ
โ โ
โ // Oops, need more space! โ
โ ptr = realloc(ptr, 10 * sizeof(int)); โ
โ โ
โ After realloc: โ
โ ptr โ [1][2][3][4][5][0][0][0][0][0] โ
โ โ Old data preserved โ New space โ
โ โ
โ โ
Old values are kept! โ
โ โ
New space is available โ
โ โ ๏ธ May move to a new location if no room to grow โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ก realloc can also SHRINK memory if you need less space!
malloc_calloc_realloc.c
#include <stdio.h>
#include <stdlib.h>
int main() {
// ============ MALLOC ============
printf("=== Using malloc ===\n");
int *arr1 = (int*)malloc(5 * sizeof(int));
if (arr1 == NULL) {
printf("malloc failed!\n");
return 1;
}
// malloc doesn't initialize - values are random!
printf("After malloc:\n");
for (int i = 0; i < 5; i++) {
printf("arr1[%d] = %d\n", i, arr1[i]); // Garbage values!
}
// Initialize manually
for (int i = 0; i < 5; i++) {
arr1[i] = (i + 1) * 10; // 10, 20, 30, 40, 50
}
// ============ CALLOC ============
printf("\n=== Using calloc ===\n");
int *arr2 = (int*)calloc(5, sizeof(int));
if (arr2 == NULL) {
printf("calloc failed!\n");
free(arr1);
return 1;
}
// calloc initializes to 0!
printf("After calloc:\n");
for (int i = 0; i < 5; i++) {
printf("arr2[%d] = %d\n", i, arr2[i]); // All zeros!
}
// ============ REALLOC ============
printf("\n=== Using realloc ===\n");
printf("Before: arr1 has 5 elements\n");
// Grow from 5 to 10 elements
int *temp = realloc(arr1, 10 * sizeof(int));
if (temp == NULL) {
printf("realloc failed!\n");
free(arr1);
free(arr2);
return 1;
}
arr1 = temp;
printf("After realloc (10 elements):\n");
printf("Old values preserved:\n");
for (int i = 0; i < 5; i++) {
printf("arr1[%d] = %d\n", i, arr1[i]); // 10, 20, 30, 40, 50
}
// Clean up
free(arr1);
free(arr2);
return 0;
}
๐๏ธ Why free() Matters
๐ The "Library Book" Analogy for Memory Leaks
MEMORY LEAK = BORROWING BOOKS BUT NEVER RETURNING
Scenario: You keep borrowing books but never return them...
Week 1:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ LIBRARY SHELVES โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ๐ โโ ๐ โโ ๐ โโ ๐ โโ ๐ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Your Books: [๐][๐] (borrowed) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Week 5:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ LIBRARY SHELVES โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ โโ โ โโ โ โโ โ โโ ๐ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Your Books: [๐][๐][๐][๐][๐][๐] โ
โ โ 10 books borrowed! โ
โ โ Never returned! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Week 10:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ LIBRARY SHELVES โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ โโ โ โโ โ โโ โ โโ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ NO MORE BOOKS AVAILABLE! โ
โ Library is "OUT OF MEMORY" โ
โ โ
โ New borrowers can't get books! โ
โ Program crashes or becomes slow! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
IN C CODE:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ void leakyFunction() { โ
โ int *arr = malloc(1000); โ
โ // Process data... โ
โ // FORGOT TO CALL FREE! โ
โ } // Memory is lost forever! โ
โ โ
โ Every call leaks 1000 bytes! โ
โ Call it 1000 times โ 1MB lost! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐จ Visual: Memory Getting Filled Up
MEMORY LEAK VISUALIZATION
HEAP at start: HEAP after leak:
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โโโ Leaked Memory โ
โ โ โ โโโ (can't use) โ
โ โ โ โโโโโโโโโโโโโโโโ โ
โ โ โ โ
โ โ โ Available space โ โ
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ
Legend:
โ = Free memory
โ = Used/leaked memory
The more you leak, the less memory is available!
โ ๏ธ Common Memory Mistakes
Mistake #1: Using Memory After Free
โ WRONG - Use After Free
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = malloc(sizeof(int)); โ
โ *ptr = 10; โ
โ free(ptr); โ
โ โ
โ printf("%d\n", *ptr); // DANGER! โ
โ โ โ
โ Using freed memory! โ
โ Could be anything now โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
RIGHT - Set to NULL after free
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = malloc(sizeof(int)); โ
โ *ptr = 10; โ
โ free(ptr); โ
โ ptr = NULL; // Now it's safe! โ
โ โ
โ if (ptr != NULL) { โ
โ printf("%d\n", *ptr); โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Mistake #2: Double Free
โ WRONG - Freeing Twice
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = malloc(sizeof(int)); โ
โ *ptr = 10; โ
โ free(ptr); โ
โ free(ptr); // CRASH! โ
โ โ โ
โ Already freed, can't free again! โ
โ โ Undefined behavior / crash โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
RIGHT - Free once, set to NULL
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *ptr = malloc(sizeof(int)); โ
โ *ptr = 10; โ
โ free(ptr); โ
โ ptr = NULL; // Prevents double free โ
โ โ
โ // Safe to call free(NULL) - does nothingโ
โ free(ptr); // No problem! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Mistake #3: Memory Leak Example
โ WRONG - Memory Leak in a Loop
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ void processData() { โ
โ for (int i = 0; i < 1000; i++) { โ
โ int *temp = malloc(1000); โ
โ // Use temp... โ
โ // FORGOT TO FREE! โ
โ } // Leaks 1000 bytes each time โ
โ } // Total leak: 1,000,000 bytes! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
RIGHT - Always Free What You Malloc
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ void processData() { โ
โ for (int i = 0; i < 1000; i++) { โ
โ int *temp = malloc(1000); โ
โ // Use temp... โ
โ free(temp); // Clean up! โ
โ } // No leak! โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Mistake #4: Not Checking malloc Return
โ WRONG - No NULL Check
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *arr = malloc(1000000000); โ
โ โ โ
โ What if this fails? โ
โ arr[0] = 10; // CRASH! NULL pointer โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
RIGHT - Always Check Return Value
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int *arr = malloc(1000000000); โ
โ if (arr == NULL) { โ
โ printf("Out of memory!\n"); โ
โ return 1; // Handle error gracefully โ
โ } โ
โ arr[0] = 10; // Safe! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
common_mistakes.c
#include <stdio.h>
#include <stdlib.h>
void safeMemoryUsage() {
// GOOD: Check malloc return
int *ptr = (int*)malloc(sizeof(int) * 100);
if (ptr == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return;
}
// Use the memory
for (int i = 0; i < 100; i++) {
ptr[i] = i * i;
}
// GOOD: Free once
free(ptr);
// GOOD: Set to NULL after free
ptr = NULL;
// Now safe - free(NULL) does nothing
free(ptr); // No crash!
}
void leakyFunction() {
// BAD: Memory leak
int *arr = (int*)malloc(1000);
// Process data...
// Oops! Forgot to free!
// Memory is lost forever
}
void useAfterFreeExample() {
int *ptr = (int*)malloc(sizeof(int));
*ptr = 42;
free(ptr);
// ptr still points to old address, but it's invalid!
// DANGER: Using freed memory!
// printf("%d\n", *ptr); // DON'T DO THIS!
// GOOD: Set to NULL
ptr = NULL;
}
int main() {
safeMemoryUsage();
// This would leak memory:
// leakyFunction();
return 0;
}
โ Memory Management Best Practices
๐ The Golden Rules of Memory
| Rule | Why It Matters | Example |
|---|---|---|
| 1. Always check if malloc succeeded | Prevents crashes when out of memory | if (ptr == NULL) { handle_error(); } |
| 2. Always free what you malloc | Prevents memory leaks | free(ptr); |
| 3. Set pointer to NULL after free | Prevents use-after-free bugs | ptr = NULL; |
| 4. Don't free twice | Prevents crashes from double-free | Setting NULL after free helps |
| 5. Free in the same scope when possible | Makes cleanup easier to track | Allocate and free in same function |
| 6. Use calloc when you need zeros | Saves initialization code | calloc(n, sizeof(int)) |
๐ฏ The Complete Pattern
โ
THE COMPLETE SAFE PATTERN
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. ALLOCATE with NULL initialization โ
โ int *ptr = NULL; โ
โ โ
โ 2. REQUEST memory from OS โ
โ ptr = malloc(size); โ
โ โ
โ 3. CHECK if allocation succeeded โ
โ if (ptr == NULL) { โ
โ // Handle error โ
โ return ERROR; โ
โ } โ
โ โ
โ 4. USE the memory โ
โ ptr[0] = 10; โ
โ โ
โ 5. FREE when done โ
โ free(ptr); โ
โ โ
โ 6. SET to NULL to prevent use-after-free โ
โ ptr = NULL; โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
MEMORY SAFETY CHECKLIST:
โก Did I check malloc/calloc/realloc return value?
โก Do I have a free() for every malloc()?
โก Did I set the pointer to NULL after free?
โก Is there any path where I return without freeing?
โก Am I accessing memory after it was freed?
best_practices_complete.c
#include <stdio.h>
#include <stdlib.h>
// Example of complete safe memory management
int* createArray(int size) {
// Step 1: Declare with NULL
int *arr = NULL;
// Step 2: Allocate
arr = (int*)malloc(size * sizeof(int));
// Step 3: Check
if (arr == NULL) {
fprintf(stderr, "Failed to allocate %d integers\n", size);
return NULL;
}
// Step 4: Use
for (int i = 0; i < size; i++) {
arr[i] = i + 1;
}
return arr; // Caller must free!
}
// Safe function that allocates and frees
void processArray() {
int *arr = createArray(10);
if (arr == NULL) {
return; // Allocation failed
}
// Use the array
printf("Array: ");
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Step 5: Free
free(arr);
// Step 6: Set to NULL
arr = NULL;
}
int main() {
printf("=== Safe Memory Example ===\n");
processArray();
printf("\nMemory handled safely!\n");
return 0;
}
๐ Quick Reference Summary
๐ Key Takeaways
MEMORY TYPES CHEAT SHEET
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ STACK MEMORY (Automatic) โ
โ โข Local variables: int x = 5; โ
โ โข Function parameters โ
โ โข Arrays: int arr[100]; โ
โ โข Allocated automatically when function starts โ
โ โข Freed automatically when function ends โ
โ โข Limited size (1-8 MB typically) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HEAP MEMORY (Dynamic) โ
โ โข malloc(size) - raw memory, uninitialized โ
โ โข calloc(n, size) - zero-initialized memory โ
โ โข realloc(ptr, new_size) - resize existing memory โ
โ โข free(ptr) - return memory to OS โ
โ โข YOU must manage it! โ
โ โข Large size available (GB) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
THE GOLDEN RULE:
"For every malloc/calloc/realloc, there must be a free()"
COMMON PATTERN:
int *ptr = malloc(size);
if (ptr == NULL) { /* handle error */ }
// ... use memory ...
free(ptr);
ptr = NULL;