Memory Management
Manual allocation and deallocation
Introduction
In this lesson, you'll learn about memory management in C. Coming from Java, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In Java, you're familiar with manual allocation and deallocation.
C has its own approach to manual allocation and deallocation, which we'll explore step by step.
The C Way
Let's see how C handles this concept. Here's a typical example:
#include <stdlib.h>
int main() {
// Stack allocation - automatic
int stackArr[100];
// Heap allocation - manual
int* heapArr = malloc(100 * sizeof(int));
Person* p = malloc(sizeof(Person));
if (heapArr == NULL || p == NULL) {
// Handle allocation failure!
return 1;
}
// Use them...
// YOU must free heap memory!
free(heapArr);
free(p);
return 0;
}Comparing to Java
Here's how you might have written similar code in Java:
// Java - automatic memory management
public class Example {
public static void main(String[] args) {
int[] arr = new int[100]; // allocated
Person p = new Person(); // allocated
// Use them...
// No need to free - garbage collector handles it
arr = null; // eligible for GC
}
}You may be used to different syntax or behavior.
No garbage collector - you must free memory
You may be used to different syntax or behavior.
malloc() can fail - always check for NULL
You may be used to different syntax or behavior.
Stack memory is automatic, heap is manual
You may be used to different syntax or behavior.
Memory leaks and double-free are common bugs
Step-by-Step Breakdown
1. Stack vs Heap
Stack memory is automatic and limited. Heap is manual but larger.
void example() {
int stackVar = 42; // stack - auto freed
int stackArr[100]; // stack - limited size
int* heapArr = malloc(1000000 * sizeof(int));
// heap - can be much larger
// but YOU must free it
free(heapArr);
} // stackVar and stackArr freed automatically2. Allocation Functions
malloc allocates bytes, calloc zeros memory, realloc resizes.
// malloc - allocate uninitialized memory
int* a = malloc(10 * sizeof(int));
// calloc - allocate and zero-initialize
int* b = calloc(10, sizeof(int));
// realloc - resize allocation
a = realloc(a, 20 * sizeof(int));
// Always free when done
free(a);
free(b);3. Common Memory Bugs
Memory bugs can cause crashes, security vulnerabilities, and hard-to-find errors.
// Memory leak - forgot to free
void leak() {
int* p = malloc(100);
// oops, no free(p)!
}
// Double free - freeing twice
void doubleFree() {
int* p = malloc(100);
free(p);
free(p); // CRASH or undefined behavior!
}
// Use after free
void useAfterFree() {
int* p = malloc(100);
free(p);
*p = 42; // DANGEROUS!
}Common Mistakes
When coming from Java, developers often make these mistakes:
- No garbage collector - you must free memory
- malloc() can fail - always check for NULL
- Stack memory is automatic, heap is manual
Key Takeaways
- No garbage collector - malloc/free are your responsibility
- Always check malloc return value for NULL
- Set pointers to NULL after free
- Memory bugs cause crashes and security holes