Rigorous, interactive visualizations covering every C concept you need — from bits to malloc — before tackling linked lists, trees, and graphs.
Variables, Data Types & Memory Layout
Every variable occupies real bytes in RAM. Understanding type sizes and memory layout is the absolute foundation before you write even the simplest data structure.
Data Type Size Explorer INTERACTIVE
Select a C type to see how many bytes it occupies in memory, its binary layout, and value range. All sizes shown for a 64-bit system.
Memory Layout — each box = 1 byte
Stack Frame Builder ANIMATE
Declare variables and watch them get placed on the stack at consecutive decreasing addresses (stack grows downward on x86-64). Notice how types of different sizes take up different amounts of space.
Stack (grows ↓)
Code
// Declare variables to see them here
Signed vs Unsigned CONCEPT
The MSB (most significant bit) acts as a sign bit in signed types. Same bit pattern, different interpretation!
8-bit: 0xFF = 11111111
signed char:-1
unsigned char:255
unsigned int u = 4294967295; // 2^32 - 1signed int s = -1;
// SAME 32 bits: 0xFFFFFFFF// Use size_t for array indices!
sizeof() Operator REFERENCE
Always use sizeof(type) instead of hardcoding sizes. Code must be portable across architectures.
A running C program has 4 memory regions. Data structures live in different regions depending on how they're created.
High addrLow addr
Stack
Local variables, function params, return addresses
Grows ↓ downward. Auto-freed on return.
↕ gap (unmapped — segfault zone)
Heap
malloc() / calloc() allocations
Grows ↑ upward. YOU must free() it.
BSS / Data Segment
Global & static variables
Text (Code) Segment
Your compiled program instructions
💡
Key rule: Linked lists, trees, and graphs use heap memory (malloc). Arrays declared locally use stack. Understanding this prevents 90% of segfaults and memory leaks.
Arrays — Contiguous Memory Blocks
Arrays are the simplest data structure and the foundation for stacks, queues, and hash tables. The key insight: arr[i] is literally pointer arithmetic.
Array Memory Visualizer INTERACTIVE
Arrays store elements at consecutive addresses. Accessing element arr[i] computes address base + i × sizeof(type) — this is O(1) random access!
Array in Memory — base address: 0x1000
int arr[] = {10, 25, 7, 42, 18, 3, 61};
// arr[i] ≡ *(arr + i)// &arr[i] ≡ arr + i (address)// addr of arr[i] = base + i × 4 (for int)// Proof: arr[2] → 0x1000 + 2×4 = 0x1008
Search Algorithm Visualizer ANIMATE
Linear Search O(n)
Binary Search O(log n)
Scans every element one by one. Works on unsorted arrays. Worst case: n comparisons.
Requires a sorted array. Eliminates half the remaining elements with each comparison. Much faster for large arrays.
Array — scanning position highlighted
intlinearSearch(int arr[], int n, int target) {
for (int i = 0; i < n; i++) {
if (arr[i] == target)
return i; // found!
}
return-1; // not found
} // O(n) worst case
intbinarySearch(int arr[], int n, int target) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2; // avoids overflow!if (arr[mid] == target) return mid;
else if (arr[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return-1; // O(log n) worst case
}
2D Arrays — Row-Major Layout CONCEPT
2D arrays are stored as one contiguous block in row-major order. Critical for adjacency matrices in graphs. Click a cell to see its 1D memory offset.
2D View (click a cell)
Linear Memory (row-major)
int M[3][4];
// Address of M[r][c] = base + (r×COLS + c) × sizeof(int)// M[1][2] offset = (1×4 + 2) × 4 = 24 bytes from base// In memory: M[0][0] M[0][1] M[0][2] M[0][3]// M[1][0] M[1][1] M[1][2] M[1][3] (contiguous!)
Pointers — The Heart of Data Structures
Without pointers there are no linked lists, no trees, no graphs. A pointer is just a variable that stores a memory address. That's it. Master this and everything else follows.
Pointer Visualizer INTERACTIVE
A pointer stores the address of another variable. Use & to get an address, * to dereference (follow the arrow to the value).
Memory Layout
int x = 99; // at address 0x2004int* ptr = &x; // ptr holds 0x2004
printf("%d", *ptr); // dereference → 99
*ptr = 200; // changes x to 200
printf("%d", x); // prints 200!
Pointer Arithmetic ANIMATE
When you do ptr++, the pointer advances by sizeof(type) bytes, not 1 byte. This is how array traversal, memcpy, and string operations work internally.
Array traversal via pointer
NULL Pointer & Safety DANGER
NULL means "points to nothing". ALWAYS check for NULL before dereferencing — NULL dereference is the most common segfault in student code.
Used when a function needs to change which node the head pointer points to — e.g., inserting at the beginning of a linked list.
int x = 42;
int* p = &x; // points to xint** pp = &p; // points to p// *pp → p (the pointer)// **pp → 42 (the value)// Used in linked list insertion:voidinsert(Node** head, int val) {
Node* n = newNode(val);
n->next = *head;
*head = n; // modifies caller's head!
}
Quick Check QUIZ
Structures — Building Data Structure Nodes
Every node in a linked list, tree, or graph IS a struct. Structs group related data — they are the DNA of every data structure you'll implement.
Struct Memory Layout with Padding INTERACTIVE
The compiler adds padding bytes to satisfy alignment requirements (an 8-byte pointer must be at an 8-byte-aligned address). This affects sizeof(struct)!
Struct Layout in Memory
Memory bytes (each square = 1 byte)
Dot (.) vs Arrow (->) Operator ANIMATE
The -> operator dereferences a pointer AND accesses a field in one step. It's just shorthand for (*ptr).field. Click on fields to highlight!
// Pointer to structNode* p = &n;
p->data = 42; // (*p).data
p->next = NULL;
// p->x ≡ (*p).x
typedef — Cleaner Syntax BEST PRACTICE
// Without typedef (verbose)structNode {
int data;
structNode* next;
};
structNode* head; // ugly!// With typedef (preferred ✓)typedef structNode {
int data;
structNode* next; // must use struct here
} Node;
Node* head; // clean!
Self-Referential Structs KEY CONCEPT
A struct can contain a pointer to another struct of the SAME type — this is how linked lists and trees work!
typedef structTreeNode {
int data;
structTreeNode* left; // left childstructTreeNode* right; // right child
} TreeNode;
// Each node points to more TreeNodes!// This creates the tree structure.
Dynamic Memory Allocation
Linked lists, trees, and hash tables grow and shrink at runtime — they MUST use heap memory. malloc/calloc/free are the only tools for this in C.
Heap Allocator Simulator INTERACTIVE
malloc() asks the OS for memory on the heap. The returned pointer is the only way to access that memory. If you lose it (without freeing) — memory leak.
// malloc — uninitialized garbage bytesint* p = (int*)malloc(4 * sizeof(int));
// calloc — zero-initialized (safer default)int* p = (int*)calloc(4, sizeof(int));
// realloc — resize (for dynamic arrays)int* tmp = (int*)realloc(p, 8*sizeof(int));
if (!tmp) { free(p); exit(1); } // don't lose p!
p = tmp;
free(p); // return to OS
p = NULL; // prevent dangling ptr!
Memory Leak Demo DANGER
Valgrind output — every BTech student should know how to read this.
$ ./program # click a button above
Linked List — Operations Visualized
This section puts everything together: structs + pointers + malloc. Watch each operation manipulate pointers step-by-step. This is the foundation before implementing stacks/queues as linked lists.
Singly Linked List Simulator FULL INTERACTIVE
Build a linked list node by node. Every operation is explained with the exact C pointer manipulation happening under the hood.
Linked List — head pointer shown on left
// Build a list by inserting values above
Traversal Pattern ESSENTIAL
The universal pattern for traversing any linked list. Used inside print, search, and length functions.
Every data structure operation (insert, delete, search) is a function. The critical distinction: C passes everything by value — to modify something, pass a pointer to it.
Call Stack Simulator INTERACTIVE
Each function call pushes a stack frame containing local variables and the return address. Stack frames are popped (destroyed) when the function returns.
Call Stack (grows ↓)
Active Code
Pass by Value vs Reference — Side by Side ANIMATE
This is the most common source of bugs in student implementations: forgetting to pass a pointer when you need to modify the original.
// By VALUE — copy madevoiddoubleIt(int x) {
x = x * 2; // only local copy!
}
int a = 5;
doubleIt(a);
// a is still 5 — BUG!
// By REFERENCE — pointer passedvoiddoubleIt(int* x) {
*x = *x * 2; // modifies original
}
int a = 5;
doubleIt(&a);
// a is now 10 ✓
Recursion — Solving Problems with Sub-Problems
Tree traversals, graph DFS, merge sort, and tower of Hanoi are all naturally recursive. Every recursive function needs: (1) a base case, (2) progress toward the base case, (3) a recursive call.
Factorial — Call Tree & Stack Depth INTERACTIVE
Watch how each recursive call pushes a new stack frame. The "unwinding" happens when the base case is hit and values return back up the call chain.
The Fibonacci call tree reveals overlapping subproblems — fib(3) is computed multiple times! This motivates dynamic programming. Red nodes = redundant computations.
Most tree/list operations are elegantly expressed recursively. This is the pattern used in tree traversals.
// Sum all values in a linked listintsumList(Node* node) {
if (node == NULL) // base casereturn0;
return node->data // current
+ sumList(node->next); // rest
}
// Think: sum = head + sum(tail)
Stack Overflow Risk DANGER
Recursion uses stack memory. A list of 10,000 nodes will create 10,000 stack frames — stack overflow! Use iteration for long lists.
// Iterative sum — O(1) stack space ✓intsumListIter(Node* head) {
int total = 0;
while (head) {
total += head->data;
head = head->next;
}
return total;
}
// Use recursion for: trees, graphs (DFS)// Use iteration for: linked list traversal
Sorting Algorithms — Visualized
Sorting is the gateway to algorithm analysis — understanding O(n²) vs O(n log n). Bubble, insertion, and selection sort are the prerequisite before merge sort (which requires recursion + arrays).
Sorting Algorithm Visualizer INTERACTIVE
Bubble Sort O(n²)
Selection Sort O(n²)
Insertion Sort O(n²)
Comparisons: 0Swaps: 0
Press Sort to begin
Complexity Comparison ANALYSIS
Algorithm
Best
Average
Worst
Space
Stable?
Bubble Sort
O(n)
O(n²)
O(n²)
O(1)
Yes ✓
Selection Sort
O(n²)
O(n²)
O(n²)
O(1)
No ✗
Insertion Sort
O(n)
O(n²)
O(n²)
O(1)
Yes ✓
Merge Sort
O(n log n)
O(n log n)
O(n log n)
O(n)
Yes ✓
Bitwise Operations
Used in hash functions, bloom filters, visited arrays in BFS/DFS, memory-efficient flags, and low-level optimizations. A bit array can store 32 boolean values in a single int.
Bit Operation Visualizer INTERACTIVE
See each operation on individual bits. For graph algorithms: a 32-bit unsigned int can replace a bool visited[32] array!
8-bit representation
Bit Tricks for Data Structures APPLICATIONS
// ── COMMON BIT TRICKS ──// 1. Check if power of 2if (n & (n-1) == 0) // power of 2// 2. Check odd/even (faster than %)if (n & 1) // odd// 3. Multiply/divide by 2
n << 1; // n × 2
n >> 1; // n ÷ 2 (floor)// 4. Swap without temp
a ^= b; b ^= a; a ^= b;
// ── BIT ARRAY (visited[] in BFS) ──unsigned int visited = 0; // 32 nodes!// Mark node i as visited
visited |= (1u << i);
// Check if node i is visitedif (visited & (1u << i)) { ... }
// Unmark node i
visited &= ~(1u << i);
// Count visited (Kernighan's trick)int count = 0;
while (visited) {
visited &= visited - 1; count++;
}