Skip to main content

Data Structures in C

Building data structures in C teaches you exactly how computers work with data. No magic, no hidden allocation — just pure memory manipulation. In languages like Python or Java, list.append(x) hides a cascade of decisions: Should we resize? How much? Where does the old memory go? In C, you make every one of those decisions yourself. That is both the burden and the superpower.

Dynamic Array (Vector)


Linked List

Singly Linked List

Intrusive Linked List (Linux Kernel Style)

In a normal linked list, the node struct wraps the data (struct Node { int data; Node *next; }). In an intrusive list, you do the opposite: you embed the list linkage inside your data structure. This is how the Linux kernel manages almost everything — process lists, file system entries, driver queues. The key advantage: zero extra allocations (the node lives inside the object), and one object can be on multiple lists simultaneously by embedding multiple list_head fields.

Hash Table


Binary Search Tree


Min Heap (Priority Queue)


Ring Buffer (Circular Queue)

A ring buffer is one of the most important data structures in systems programming. It appears everywhere: UART receive buffers in embedded systems, audio sample buffers, network packet queues, and the Linux kernel’s kfifo. The key insight is that both the producer and consumer only move forward — the buffer wraps around using modular arithmetic, so it reuses memory without any allocation or copying.

Generic Data Structure with void*


Exercises

1

LRU Cache

Implement an LRU cache using a hash map and doubly linked list.
2

Red-Black Tree

Implement a self-balancing red-black tree with insert and delete.
3

Graph with Adjacency List

Implement a graph with BFS and DFS traversals.
4

Trie

Implement a trie for efficient string prefix matching.

Next Up

Undefined Behavior

Understand the dragons lurking in C