data-structures · intermediate · ~15 min
Implement circular ring buffer queues with wrap-around head and tail indices.
Circular ring buffers provide bounded FIFO queuing with constant time O(1) push and pop operations without shifting memory elements.
Given the ring buffer structure:
typedef struct {
int *data;
size_t capacity;
size_t head;
size_t tail;
size_t count;
} RingBuffer;
Implement:
int rb_push(RingBuffer *rb, int val);
int rb_pop(RingBuffer *rb, int *out);
int rb_peek(const RingBuffer *rb, int *out);
rb_push:rb == NULL or rb->count == rb->capacity, return -1 (buffer full).val into rb->data[rb->tail].rb->tail = (rb->tail + 1) % rb->capacity.rb->count and return 0.rb_pop:rb == NULL or out == NULL or rb->count == 0, return -1 (buffer empty).rb->data[rb->head] into *out.rb->head = (rb->head + 1) % rb->capacity.rb->count and return 0.rb_peek:rb == NULL or out == NULL or rb->count == 0, return -1.rb->data[rb->head] into *out without modifying head or count.0.int store[3];
RingBuffer rb = { .data = store, .capacity = 3, .head = 0, .tail = 0, .count = 0 };
rb_push(&rb, 10); rb_push(&rb, 20);
int v;
rb_pop(&rb, &v); // v == 10
rb: pointer to RingBuffer; val: int; out: pointer to int destination.
Returns 0 on success, -1 on buffer full/empty or NULL pointer.
O(1) operations. Use modular arithmetic modulo capacity.
#include <stddef.h>
typedef struct {
int *data;
size_t capacity;
size_t head;
size_t tail;
size_t count;
} RingBuffer;
int rb_push(RingBuffer *rb, int val) {
(void)rb; (void)val;
return -1;
}
int rb_pop(RingBuffer *rb, int *out) {
(void)rb; (void)out;
return -1;
}
int rb_peek(const RingBuffer *rb, int *out) {
(void)rb; (void)out;
return -1;
}
Forgetting modulo capacity wrap-around; forgetting to decrement count on pop.
Pushing to full buffer fails; popping from empty buffer fails; head wraps around capacity.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.