How does the following look for doing a string replace in C? Is this approach more common than allocating memory within the function and returning a new string pointer, or is the bring-your-own-buffer more common?
#include <stdio.h>
#include <string.h>
// return size of string, -1 if error such as buffer too small
// no memory is allocated here, buffer needs to be passed in
// Example: str_replace("Replace me", "me", "ME", buffer, 64);
// Returns: 10, buffer is now "Replace ME".
ssize_t
str_replace (
const char* input_str,
const char* from,
const char* to,
char* output_buffer,
size_t max_size
) {
size_t input_len = strlen(input_str);
size_t from_size = strlen(from);
size_t to_size = strlen(to);
// get the output string length;
size_t output_len = input_len;
char* str_iterator = (char*) input_str;
while ((str_iterator=strstr(str_iterator, from))) {
output_len += (to_size - from_size);
str_iterator += from_size;
}
if (output_len > max_size) {
fprintf(stderr, "Buffer too small for output string.\n");
return -1;
}
// reset str_iterator, make sure output_buffer is clear
str_iterator = (char*) input_str;
output_buffer[0] = '\0';
// copy to output buffer
// 1. Find the first match of `from` in `input_str` (advancing pointer on input_buffer along way)
// 2. Copy the input_str up until the first match to output_buffer
// 3. Copy `from` into output_buffer (advance string)
// 4. Advance input_buffer pointer by size of `from`
// 5. Repeat 2-5 until no more matches
// 6. Copy remainder of input_str to output_buffer
for (char* match; (match=strstr(str_iterator, from)); str_iterator+= (match-str_iterator) + from_size) {
strncpy(output_buffer, str_iterator, match-str_iterator);
output_buffer += (match-str_iterator);
strncpy(output_buffer, to, to_size);
output_buffer += to_size;
}
// copy remainder
if (strlen(str_iterator))
strcpy(output_buffer, str_iterator);
return output_len;
}
int main(void)
{
char buffer[50];
ssize_t out_size = str_replace("Replace me", "me", "ME", buffer, 50);
if (out_size == -1)
printf("Nope!\n");
else
printf("Response size: %zu.\nResponse string: %s\n", out_size, buffer);
}
$ gcc logmain.c -o log; ./log
Response size: 10.
Response string: Replace ME
And another alternative:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// same as above but now with malloc
char* str_replace2(const char* input, const char* from, const char* to)
{
size_t input_len = strlen(input);
size_t from_size = strlen(from);
size_t to_size = strlen(to);
char* str_iterator = (char*) input;
// get the output string length;
size_t output_len = input_len;
while ((str_iterator=strstr(str_iterator, from))) {
output_len += (to_size - from_size);
str_iterator += from_size;
}
char *str_out = malloc(output_len);
char * const str_out_start = str_out; // const for emphasis it doesn't change
if (!str_out) {
fprintf(stderr, "Cannot malloc str of size %zu", output_len);
return NULL;
}
// write to output str
str_iterator = (char*) input;
for (char* match; (match=strstr(str_iterator, from)); str_iterator+= (match-str_iterator) + from_size) {
strncpy(str_out, str_iterator, match-str_iterator);
str_out += (match-str_iterator);
strncpy(str_out, to, to_size);
str_out += to_size;
}
// copy remainder
if (strlen(str_iterator))
strcpy(str_out, str_iterator);
return str_out_start;
}
Additionally, where are comments usually put in C? Above the function? In the function?