Fundamental data structures in C: linked list, stack, and queue.
π What to learn on this page
β Must-know essentials
Linked list: each node points to the next
Stack: last-in first-out (LIFO)
Queue: first-in first-out (FIFO)
β Read if you have time
Trees and hash tables
Complexity: O(n), O(1)
Comparison with STL / standard libraries
What is a Data Structure? β Designing How Data is Arranged
A data structure defines how data is laid out in memory and how you work with it. Arrays are a data structure themselves, but plenty of situations make arrays alone awkward to use.
Limitations of arrays
Slow middle/front insertion
Inserting near the front forces every later element to shift. With a million items, that's a million shifts.
Fixed size
The size is locked in at declaration time, which makes data that grows and shrinks awkward to handle (malloc helps, but it's extra work).
Common data structures
Structure
Characteristic
Example use
Linked list
Nodes linked by pointers; fast insertion/deletion
Ordered data with frequent insert/remove
Stack
Last-in, first-out (LIFO)
Function calls, Undo history
Queue
First-in, first-out (FIFO)
Print queue, task scheduling
All of these are built from structs, pointers, and malloc. This lesson brings together everything we've learned so far!
Linked List β A Chain Connected by Pointers
A linked list is a sequence where each element (a node) holds some data plus a pointer to the next node.
Node definition
typedefstructNode {
int data; // the stored datastructNode *next; // pointer to the next node
} Node;
Picture of memory
10
nextβ
β
20
nextβ
β
30
nextβ
β
NULL
Key operations
// (1) Create a nodeNode* createNode(int val) {
Node *n = malloc(sizeof(Node));
n->data = val;
n->next = NULL;
return n;
}
// (2) Insert at the front (O(1) β fast!)voidpushFront(Node **head, int val) {
Node *n = createNode(val);
n->next = *head; // new node's next = old head
*head = n; // head now points to new node
}
// (3) Print all elementsvoidprintList(Node *head) {
for (Node *p = head; p != NULL; p = p->next)
printf("%d β ", p->data);
printf("NULL\n");
}
// (4) Free the memory (forgetting leaks!)voidfreeList(Node *head) {
while (head) {
Node *tmp = head->next;
free(head);
head = tmp;
}
}
Front insertion
O(1) β very fast
Search
O(n) β walk from the head
Vs. arrays
No indexed access; random access isn't its strength.
Stack β Last In, First Out (LIFO)
A stack pops the most recently pushed item first. Think of stacking plates. The call stack that tracks function calls works the same way.
Stack visualization
10
20
30
β TOP (items come off here)
// push: add to the topvoidpush(Node **top, int val) {
Node *n = createNode(val);
n->next = *top;
*top = n;
}
// pop: remove from the topintpop(Node **top) {
if (*top == NULL) return -1;
Node *tmp = *top;
int val = tmp->data;
*top = tmp->next;
free(tmp);
return val;
}
Everyday examples: the browser Back button, Ctrl+Z (Undo), and the call stack that tracks function calls β all of these use a stack under the hood.
Queue β First In, First Out (FIFO)
A queue removes items in the same order they went in β just like a checkout line.
Queue visualization
Out β
10
20
30
β In
// enqueue: add to the tailvoidenqueue(Node **head, Node **tail, int val) {
Node *n = createNode(val);
if (*tail) (*tail)->next = n;
else *head = n;
*tail = n;
}
// dequeue: remove from the headintdequeue(Node **head, Node **tail) {
if (!*head) return -1;
Node *tmp = *head;
int val = tmp->data;
*head = tmp->next;
if (!*head) *tail = NULL;
free(tmp);
return val;
}
Everyday examples: printer queues, OS task schedulers, and chat message ordering.
Array vs Linked List vs Stack vs Queue
Operation
Array
Linked list
Stack
Queue
Insert at front
O(n)
O(1)
β
β
Append at back
O(1)
O(1)*
O(1)
O(1)
Random access
O(1)
O(n)
β
β
Insert in middle
O(n)
O(1)β
β
β
* with a tail pointer. β when the insertion point is known.
Linked List Demo
Use the buttons to add and remove elements from a linked list, and watch the structure update in real time.