Implementing a circular buffer (also known as a ring buffer) using C-style strings can be useful for scenarios where you need to store a fixed number of recent messages or log entries. Here's an example of how to implement a simple circular buffer:
#include <iostream>
#include <cstring>
// Custom strlcpy implementation
size_t strlcpy(
char* dst, const char* src, size_t dstsize
) {
size_t srclen = std::strlen(src);
size_t copylen =
(srclen >= dstsize) ? dstsize - 1 : srclen;
if (dstsize > 0) {
std::memcpy(dst, src, copylen);
dst[copylen] = '\0';
}
return srclen;
}
class CircularBuffer {
private:
static const int MAX_ENTRIES{5};
static const int MAX_STRING_LENGTH{50};
char buffer[MAX_ENTRIES][MAX_STRING_LENGTH];
int head{0};
int count{0};
public:
void add(const char* str) {
strlcpy(buffer[head], str, MAX_STRING_LENGTH);
head = (head + 1) % MAX_ENTRIES;
if (count < MAX_ENTRIES) count++;
}
void print() const {
for (int i = 0; i < count; ++i) {
int index{(head - count + i + MAX_ENTRIES) %
MAX_ENTRIES};
std::cout << buffer[index] << '\n';
}
}
};
int main() {
CircularBuffer cb;
cb.add("First message");
cb.add("Second message");
cb.add("Third message");
std::cout << "After adding 3 messages:\n";
cb.print();
cb.add("Fourth message");
cb.add("Fifth message");
cb.add("Sixth message");
std::cout << "\nAfter adding 3 more messages:\n";
cb.print();
}
After adding 3 messages:
First message
Second message
Third message
After adding 3 more messages:
Second message
Third message
Fourth message
Fifth message
Sixth message
Let's break down this implementation:
CircularBuffer
class with a fixed-size 2D array of characters to store our strings.head
variable keeps track of where to insert the next string.count
variable tracks how many strings are currently in the buffer.add()
method:
head
position.strncpy()
to prevent buffer overflows.head
and count
.print()
method iterates through the buffer, starting from the oldest entry.This implementation has some limitations:
We can enhance this implementation to make it more flexible and powerful:
#include <iostream>
#include <memory>
#include <algorithm>
#include <cstring>
class CircularBuffer {
private:
std::unique_ptr<char[]> buffer;
size_t bufferSize;
size_t maxEntries;
size_t head{0};
size_t count{0};
size_t getIndex(size_t position) const {
return (head - count + position + maxEntries) %
maxEntries;
}
public:
CircularBuffer(size_t entries, size_t entrySize)
: buffer(
std::make_unique<char[]>(entries * entrySize)
),
bufferSize(entrySize),
maxEntries(entries) {}
void add(const char* str) {
std::fill(&buffer[head * bufferSize],
&buffer[head * bufferSize + bufferSize],
'\0');
std::copy_n(str,
std::min(bufferSize - 1, std::strlen(str)),
&buffer[head * bufferSize]);
head = (head + 1) % maxEntries;
if (count < maxEntries) count++;
}
const char* get(size_t position) const {
if (position >= count) return nullptr;
return &buffer[
getIndex(position) * bufferSize];
}
void print() const {
for (size_t i = 0; i < count; ++i) {
std::cout << get(i) << '\n';
}
}
size_t size() const { return count; }
size_t capacity() const { return maxEntries; }
};
int main() {
// 5 entries, each up to 50 characters
CircularBuffer cb(5, 50);
cb.add("First message");
cb.add("Second message");
cb.add("Third message");
cb.add("Fourth message");
cb.add("Fifth message");
cb.add("Sixth message");
std::cout << "Buffer contents:\n";
cb.print();
std::cout << "\nThird oldest message: "
<< cb.get(2) << '\n';
std::cout << "Buffer size: "
<< cb.size() << '\n';
std::cout << "Buffer capacity: "
<< cb.capacity() << '\n';
}
Buffer contents:
Second message
Third message
Fourth message
Fifth message
Sixth message
Third oldest message: Fourth message
Buffer size: 5
Buffer capacity: 5
This enhanced version:
get()
method for accessing individual entries.size()
and capacity()
methods for querying the buffer state.Remember, while this implementation uses C-style strings for demonstration, in real-world C++ applications, using std::string
and std::vector
or std::array
might be more appropriate and safer.
Answers to questions are automatically generated and may not have been reviewed.
A guide to working with and manipulating C-style strings, using the
library