First in, first out — and the array that runs out early
A plain array queue reports full even with empty slots at the start. The circular queue fixes this by wrapping indices with the modulo operator.
After this lesson
You should be able to
- Implement enqueue and dequeue using front and rear indices.
- Explain why a plain array queue reports false full.
- Use the modulo operator to wrap indices in a circular queue.
Try it before you read
Try it live
Queue is empty.
Insert at one end, remove from the other
A queue restricts access differently from a stack: insertion happens at rear, removal happens at front, and the first value in is always the first one out. A ticket line works this way — whoever joined first is served first.
The natural array version keeps two indices: front points at the oldest element, rear points at the newest. enqueue advances rear and writes; dequeue reads at front and advances it.
#define CAPACITY 5
int data[CAPACITY];
int front = 0, rear = -1, count = 0;
int is_empty(void) { return count == 0; }
int is_full(void) { return count == CAPACITY; }The false-full problem
If rear simply keeps advancing and never comes back, it eventually reaches the last array slot and is_full reports true — even if you have long since dequeued everything from the front and the first slots sit empty. The space at the beginning is real but unreachable with a plain forward-only rear.
This is not a bug you introduced — it is a limitation of the straightforward design. The fix is to let indices wrap back to 0 once they pass the end.
Wrapping with modulo
% from your C course does exactly what is needed: (rear + 1) % CAPACITY advances rear normally until it reaches the last index, then wraps to 0 on the next step instead of running off the array. This is the same remainder operator, applied to indices instead of numbers.
count is what makes full and empty distinguishable — with wrapping indices alone, front == rear could mean either, so the count of elements currently held resolves the ambiguity directly.
void enqueue(int value)
{
if (is_full()) { printf("Queue full\n"); return; }
rear = (rear + 1) % CAPACITY;
data[rear] = value;
count++;
}
int dequeue(void)
{
if (is_empty()) { printf("Queue empty\n"); return -1; }
int value = data[front];
front = (front + 1) % CAPACITY;
count--;
return value;
}Try it yourself
Build a circular queue of capacity 4, then enqueue 6 values one at a time, dequeuing whenever the queue is full before continuing, and print each dequeued value.
Need a hint?
This forces rear to wrap around at least once — trace the front and rear indices by hand first if the output surprises you.
Check the worked solution
Once count reaches CAPACITY the first time, the loop dequeues before the next enqueue, which is exactly why count rather than a raw comparison of front and rear is checked — the indices themselves wrap and would otherwise be ambiguous about whether the queue is full or empty at that instant.
#include <stdio.h>
#define CAPACITY 4
int data[CAPACITY];
int front = 0, rear = -1, count = 0;
int is_empty(void) { return count == 0; }
int is_full(void) { return count == CAPACITY; }
void enqueue(int value)
{
rear = (rear + 1) % CAPACITY;
data[rear] = value;
count++;
}
int dequeue(void)
{
int value = data[front];
front = (front + 1) % CAPACITY;
count--;
return value;
}
int main(void)
{
int values[6] = {10, 20, 30, 40, 50, 60};
for (int i = 0; i < 6; i++) {
if (is_full()) {
printf("Full — dequeued %d\n", dequeue());
}
enqueue(values[i]);
printf("Enqueued %d\n", values[i]);
}
return 0;
}Quick check
In a plain (non-circular) array queue, why can it report full even when several slots at the start are empty?
Why this lesson exists
Syllabus mapping
Queues- operations · Queue Algorithm · Queue ADT
Maps to course outcomes CO1, CO3, CO4.