This is a type-safe, header-only implementation of a std::basic_string
-like string in plain C code.
It can be considered an offshoot of the c-vector library and is intended to be binary compatible with it. Many sequences of the c-string
library essentially correspond to the c-vector
library code. All credits go to eteran and contributors.
While the c-vector
library implements macros to emulate methods of a std::vector
, the c-string
library is specialized for null-terminated strings of characters. Its macros emulate std::basic_string
methods. A few additional features are implemented that don't have an equivalent for a std::basic_string
.
The cstring_array
API extension is for vectors of cstring
. It supports tokenization (also known as split
) and concatenation (also known as join
).
Just like the cvector
, a cstring
is prefixed with metadata, in the tradition of a length-prefixed string implementation.
The members of the cstring
metadata are found at the same offset as those of a cvector
. They count all characters (incl. the terminating null) which makes a cstring
interchangeable with a cvector
of the same set of consecutive characters. Unlike the cvector
macros (and as is usual for strings) the cstring
macros, which return size and capacity, do not count the string terminator.
The user is given a pointer to the first character of the actual string. This way a cstring
can be used with the C string and I/O library functions that don't modify its content, as well as whith those of the platform API.
Example:
#include "cstring.h"
#include <stdio.h>
int main(void) {
// Declaration of a null-string. The initialization with NULL is critical.
cstring_string_type(char) str = NULL;
// Assign string "abc".
cstring_assign(str, "abc", 3);
printf("1)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Append string "hi".
cstring_append(str, "hi", 2);
printf("2)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Insert string "defg" at offset 3 (between 'c' and 'h').
cstring_insert(str, 3, "defg", 4);
printf("3)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Erase 4 characters at offset 1.
cstring_erase(str, 1, 4);
printf("4)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Add an 'x' at the end of the string.
cstring_push_back(str, 'x');
printf("5)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Replace two characters at offset 3 with three 'z' characters.
cstring_replace(str, 3, 2, "zzz", 3);
printf("6)\nString: %s\nLength: %zu\nCapacity: %zu\n\n", str, cstring_length(str), cstring_capacity(str));
// Copy a 4-character substring from offset 2.
cstring_string_type(char) str2 = NULL;
cstring_substring(str, 2, 4, str2);
printf("7)\nString2: %s\nLength: %zu\nCapacity: %zu\n\n", str2, cstring_length(str2), cstring_capacity(str2));
// Free allocated memory.
cstring_free(str2);
cstring_free(str);
return 0;
}
std::basic_string | cstring |
---|---|
std::basic_string<type> str{}; |
cstring_string_type(type) str = NULL; 1,cstring_literal(name, type, lit) 2,cstring_init(name, type) 3 |
Destructor | cstring_free(str) |
str.assign(s, count) |
cstring_assign(str, s, count) |
str.at(pos) |
cstring_at(str, pos) |
str[pos] |
str[pos] |
str.front() |
cstring_front(str) |
str.back() |
cstring_back(str) |
str.data() , str.c_str() |
str |
str.begin() |
cstring_begin(str) |
str.end() |
cstring_end(str) |
str.empty() |
cstring_empty(str) |
str.size() , str.length() |
cstring_size(str) , cstring_length(str) |
std::basic_string<type>::max_size() |
cstring_max_size(type) |
str.reserve(n) |
cstring_reserve(str, n) |
str.capacity() |
cstring_capacity(str) |
str.shrink_to_fit() |
cstring_shrink_to_fit(str) |
N/A | cstring_unsafe_set_size(str, size) 4 |
str.clear() |
cstring_clear(str) |
str.insert(index, s, count) |
cstring_insert(str, index, s, count) |
str.erase(index, count) |
cstring_erase(str, index, count) |
str.push_back(ch) |
cstring_push_back(str, ch) |
str.pop_back() |
cstring_pop_back(str) |
str.append(s, count) |
cstring_append(str, s, count) |
str.replace(pos, count, s, count2) |
cstring_replace(str, pos, count, s, count2) |
from.copy(to, npos, 0) |
cstring_copy(from, to) 5 |
str.resize(count, ch) |
cstring_resize(str, count, ch) |
str.swap(other) |
cstring_swap(str, other) |
N/A | cstring_trim(str, value, mode) 6 |
N/A | cstring_fix(str, length, value, mode) 7 |
N/A | cstring_reverse(str) 8 |
offset = str.find(s, pos, count) |
cstring_find(str, pos, s, count, offset) |
offset = str.rfind(s, pos, count) |
cstring_rfind(str, pos, s, count, offset) |
offset = str.find_first_of(s, pos, count) |
cstring_find_first_of(str, pos, s, count, offset) |
offset = str.find_first_not_of(s, pos, count) |
cstring_find_first_not_of(str, pos, s, count, offset) |
offset = str.find_last_of(s, pos, count) |
cstring_find_last_of(str, pos, s, count, offset) |
offset = str.find_last_not_of(s, pos, count) |
cstring_find_last_not_of(str, pos, s, count, offset) |
order = str1.compare(str2) |
cstring_compare(str1, str2, order) |
found = str.starts_with(s) |
cstring_starts_with(str, s, count, found) |
found = str.ends_with(s) |
cstring_ends_with(str, s, count, found) |
found = str.contains(s) |
cstring_ends_with(str, s, count, found) |
to = from.substring(pos, count) |
cstring_substring(from, pos, count, to) |
A cstring_array
is a NULL pointer-terminated vector of cstring
.
The concept is similar to the vector of arguments in int main(int argc, char *argv[])
. While argv
is guaranteed to be NULL pointer-terminated, this terminator is not counted in argc
.
Like a cstring
, a cstring_array
is a heap-allocated and metadata-prefixed object.
Macro | Description |
---|---|
cstring_array_type(type) arr = NULL |
Declare a vector of cstring using the specified character type. |
cstring_split(str, max_tok, ptr, count, ret_array) |
Tokenize str into a vector of cstring . |
cstring_array_free(arr) |
Recursively free all memory associated with the vector. |
cstring_array_at(arr, pos) |
Return the string pointer at position pos in the cstring_array. |
cstring_array_front(arr) |
Return the string pointer to the first string in the cstring_array. |
cstring_array_back(arr) |
Return the string pointer to the last string in the cstring_array. |
cstring_array_begin(arr) |
Return an iterator to first string of the vector. |
cstring_array_end(arr) |
Return an iterator to one past the last string of the vector. |
cstring_array_empty(arr) |
Return non-zero if the vector is empty. |
cstring_array_size(arr) |
Get the current length of the vector. |
cstring_array_max_size(type) |
Get the maximum number of elements a vector of strings of the specified character type is able to hold. |
cstring_array_reserve(arr, n) |
Request that the vector capacity be at least enough to contain n strings. |
cstring_array_capacity(arr) |
Get the current capacity of the vector. |
cstring_array_shrink_to_fit(arr) |
Request the container to reduce its capacity to fit its size. |
cstring_array_clear(arr) |
Erase all of the strings in the vector. |
cstring_array_insert(arr, pos, ptr, count) |
Insert a string at position pos into the vector. |
cstring_array_erase(arr, pos, n) |
Remove the strings beginning at offset pos from the cstring_array. |
cstring_array_push_back(arr, ptr, count) |
Add a string to the end of the vector. |
cstring_array_pop_back(arr) |
Remove the last string from the cstring_array. |
cstring_array_copy(from, to) |
Copy a cstring_array. |
cstring_array_resize(arr, n, ptr, count) |
Resize the container to contain count strings. |
cstring_array_swap(arr, other) |
Exchange the content of the cstring_array by the content of another cstring_array of the same type. |
cstring_array_slice(from, pos, n, to) |
Copy a part of a vector. |
cstring_array_join(arr, ptr, count, ret_str) |
Concatenate the strings of a vector using the specified joiner. |
Neil Henning's unit test header is used to verify the proper functionality of all API macros.
Footnotes
-
Initializes a NULL string. Nothing similar for
std::basic_string
. ↩ -
Declares a static cstring literal of
const type
. This is comparable with a C++20constexpr std::basic_string
. ↩ -
Allocates and initializes a zero-length string. ↩
-
Manually updates the size property after an update of the string buffer in a third party API. ↩
-
This creates a duplicate of the string. For copying a substring see
cstring_substring()
. ↩ -
Removes contiguous occurrences of the specified character from the begin and/or the end of a cstring. ↩
-
Updates the cstring to a fixed length by either padding or shortening. ↩
-
Reverses the character order in the cstring. ↩