You are working with a pre-filled circular buffer of 10 elements.
The buffer is structured as:
typedef struct {
int buffer[10];
int head; // Write pointer
int tail; // Read pointer
int count; // Number of unread bytes
int capacity; // Always 10
} CircularBuffer;Your Task
Implement this function:
void read_bytes(CircularBuffer *cb, int n);This function should:
Example-1
Input: n = 4
Initial Buffer:
buffer = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
head = 3
tail = 7
count = 6
Output:
80 90 100 10
Tail: 1
Example-2
Input: n = 5
Same setup, but count = 2
Output:
80 90 NULL NULL NULL
Tail: 9
A circular buffer (ring buffer) is a fixed-size, first-in-first-out (FIFO) data structure where data is written at the head and read from the tail, and both wrap around when reaching the end.
In embedded firmware, circular buffers are heavily used in:
#define BUFFER_SIZE 50
typedef struct {
uint8_t buffer[BUFFER_SIZE];
uint8_t head;
uint8_t tail;
uint8_t count;
} CircularBuffer;void init_buffer(CircularBuffer *cb) {
cb->head = 0;
cb->tail = 0;
cb->count = 0;
}bool buffer_push(CircularBuffer *cb, uint8_t data) {
if (cb->count == BUFFER_SIZE) {
return false; // Buffer Full
}
cb->buffer[cb->head] = data;
cb->head = (cb->head + 1) % BUFFER_SIZE;
cb->count++;
return true;
}Wrap-around logic via modulus keeps head circular.
bool buffer_pop(CircularBuffer *cb, uint8_t *data) {
if (cb->count == 0) {
return false; // Buffer Empty
}
*data = cb->buffer[cb->tail];
cb->tail = (cb->tail + 1) % BUFFER_SIZE;
cb->count--;
return true;
}bool buffer_peek(CircularBuffer *cb, uint8_t *data) {
if (cb->count == 0) return false;
*data = cb->buffer[cb->tail];
return true;
}bool buffer_is_full(CircularBuffer *cb) {
return cb->count == BUFFER_SIZE;
}
bool buffer_is_empty(CircularBuffer *cb) {
return cb->count == 0;
}
int main() {
CircularBuffer cb;
init_buffer(&cb);
// Insert elements
for (int i = 0; i < 6; i++) {
buffer_push(&cb, i * 10); // 0, 10, 20, ...
}
// Peek
uint8_t peek_val;
if (buffer_peek(&cb, &peek_val)) {
printf("Peek: %d\n", peek_val); // Should be 0
}
// Pop values
uint8_t val;
while (buffer_pop(&cb, &val)) {
printf("Popped: %d\n", val);
}
return 0;
}
Assume:
If we pop twice:
| Use Case | Where Used |
|---|---|
| UART Rx buffer | Interrupt-based serial read |
| ADC sampling buffer | DMA circular conversion |
| Logging or debug buffer | Time-ordered messages |
| Audio or signal processing | Rolling sample window |