With just head and tail, the empty condition is head == tail. But if you write into every slot, head wraps all the way around and lands back on tail, so head == tail also represents full. The two states are indistinguishable, and code that treats head == tail as empty will think a completely full buffer is empty (or vice versa), corrupting it. Two standard fixes: (1) sacrifice one slot, define full as (head + 1) % CAP == tail, so the buffer holds at most CAP−1 items and head == tail unambiguously means empty; simple and needs no extra state. (2) Keep an explicit count of items, count == 0 empty, count == CAP full, which uses all CAP slots but adds a counter that both producer and consumer modify, reintroducing a shared variable that needs synchronization. For single-producer/single-consumer designs the sacrifice-one-slot approach is popular precisely because it avoids that shared counter.
Data Structures & Algorithms · Interview question
The buffer looks "empty" and "full" in the same state. Explain and fix.
A strong answer
What a weak answer sounds like
You know the answer. Do you know what gets you dinged?
Pro breaks down the answer most candidates actually give to this question — and the specific reason an interviewer marks it down. It’s the difference between sounding correct and sounding senior, on all 472 questions.
From the lesson
Ring Buffers
The fixed-memory FIFO behind every UART driver: head and tail indices wrapping a static array, O(1) push/pop, and the full-vs-empty trick, plus the lock-free single-producer/consumer pattern.