Expert · Data structures in C · topic 48 of 60 · 30 min
Queues and circular buffers
Explanation
FIFO
A queue serves items in arrival order, like a ticket counter line. Typical uses: print jobs, tasks waiting for a worker, messages between parts of a program, and bytes arriving from hardware faster than the program reads them.
Why a circular buffer?
naive array queue after some enqueues and dequeues:
[ x | x | x | 40 | 50 | 60 | | ]
head tail
the slots before head are wasted; soon tail reaches the end even though space is free
circular buffer: the indexes wrap around to the start
[ 70 | 80 | | 40 | 50 | 60 ]
tail head (capacity 6, count 5)Implementation
#define QCAP 8
typedef struct {
int buf[QCAP];
int head; /* index of the oldest item */
int tail; /* index where the next item goes */
int count; /* items stored */
} Queue;
void q_init(Queue *q) { q->head = q->tail = q->count = 0; }
int enqueue(Queue *q, int v) {
if (q->count == QCAP) return -1; /* full */
q->buf[q->tail] = v;
q->tail = (q->tail + 1) % QCAP; /* wrap around */
q->count++;
return 0;
}
int dequeue(Queue *q, int *out) {
if (q->count == 0) return -1; /* empty */
*out = q->buf[q->head];
q->head = (q->head + 1) % QCAP;
q->count--;
return 0;
}Without a count, head == tail is ambiguous (empty or full?). The two standard fixes are keeping a count, as above, or always leaving one slot unused so "full" means (tail + 1) % cap == head. When the capacity is a power of two, (i + 1) & (cap - 1) replaces the % and is a little faster, a trick common in firmware.
Embedded use: a UART receive buffer
A microcontroller's serial port can receive bytes at any moment. An interrupt routine (module 12) stores each byte into a circular buffer as it arrives, and the main loop reads bytes out when it has time. Neither side ever moves data around; they just advance their own index.
Linked-list queues
A queue can also be a linked list with head and tail pointers: enqueue appends at the tail in O(1), dequeue removes from the head in O(1), and there is no fixed capacity, at the cost of a malloc per item.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Queues and circular buffers · 1/6
In this lesson you will build queues and circular buffers.
Prefer a video by a teacher? Find free videos on “circular buffer ring buffer queue in c embedded uart” on YouTube ↗
In real life: Keeping the last 60 heart-rate readings
A fitness band stores the most recent 60 heart-rate readings in a circular buffer that OVERWRITES the oldest value when full. The display can always draw the last minute, and memory use never grows.
#define N 60
uint8_t bpm[N];
int next = 0, filled = 0;
void add_reading(uint8_t v) {
bpm[next] = v;
next = (next + 1) % N;
if (filled < N) filled++;
}Practice (0/3 done)
In a circular buffer of capacity 5 with tail = 4, where does the next item go after enqueue moves tail with (tail + 1) % 5?
The same circular-buffer algorithm in JavaScript, which runs here: write createQueue(capacity) returning an object with enqueue(v) (returns false when full), dequeue() (returns undefined when empty) and size(). Use a fixed array with head, tail and count indexes and % capacity, NOT array push/shift.
Implement the circular-buffer Queue in C with capacity 8 (count-based), plus a second version that leaves one slot empty instead of using count. Write a test that fills the queue, empties it, then interleaves enqueue/dequeue 20 times to force the indexes to wrap, checking the FIFO order every time.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Binary search treesData structures in C · same module
- Queues and dequesData Structures and Algorithms (DSA) for interviews · Stacks, queues and linked lists
- Stacks and queuesPython Programming · Algorithms, data structures and testing
- Queues, stacks and priority queuesJava Programming (Core to Spring Boot) · The collections framework
- Channels: passing data between goroutinesGo Programming (backend and cloud) · Concurrency: goroutines, channels and context
- set, stack, queue, deque and priority_queueC++ Programming (modern C++ and DSA) · The Standard Template Library (STL)
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Which order does a queue follow?
Answer: FIFO
First in, first out.
Without a count, why is head == tail ambiguous in a circular buffer?
Answer: It can mean either empty or full
Use a count or keep one slot empty.
Where are circular buffers common?
Answer: Embedded systems, e.g. serial (UART) receive buffers
Interrupts fill them; the main loop drains them.
With capacity 16, which expression can replace (i + 1) % 16?
Answer: (i + 1) & 15
For powers of two, & (cap - 1) equals % cap.
A circular queue has capacity 4, head = 3 and count = 2. Which slot does the next enqueue use?Related
Answer: 1
(3 + 2) % 4 = 1. The items sit in slots 3 and 0; the next one goes in slot 1.
From Queues and deques
Which is the best tool for a large FIFO queue in Python?Related
Answer: collections.deque with append and popleft
deque adds and removes at both ends in O(1). list.pop(0) shifts every item, which is O(n).
From Stacks and queues
Which removes and returns the head of a Queue, or null if it is empty?Related
Why does push_front take Node **head?Related
Answer: To change the caller's head pointer
The function must update the caller's pointer.
From Singly linked lists
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Data structures in C” before its exam: Binary search trees, Hash tables.
- Module 10 exam: Data structures in C · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Debugging and tools. 60 topics left in the course before the final exam.