Skip to content

Instantly share code, notes, and snippets.

@bnm3k
Last active April 23, 2020 08:14
Show Gist options
  • Save bnm3k/1766a650305b943782da9592d0c7d8b8 to your computer and use it in GitHub Desktop.
Save bnm3k/1766a650305b943782da9592d0c7d8b8 to your computer and use it in GitHub Desktop.
Procedure demonstrating joining of strings in C using snprintf
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Takes an array of c-strings and joins them into a single string placed in buf
* If the size of buf, i.e. buf_len, suffices, join_strs returns a non_negative
* integer that's equal to the total chars written to the buf, minus the
* null terminating character '\0'. The caller can also supply a sep argument
* which is a string that'll be placed between each string during joining
* If the caller doesn't want any separator between each string, they can
* pass NULL to sep instead.
* However, if not successful, join_strs returns a negative value, ie strictly
* less than 0
*/
int join_strs(char *buf, int buf_len, char **str_arr, int str_arr_len, const char *sep) {
int total_chars_written = 0;
if (buf_len <= 0) {
return buf_len - 1;
}
if (sep == NULL) sep = "";
for (int i = 0; i < str_arr_len; i++) {
if (i == str_arr_len - 1) sep = "";
int chars_written = snprintf(buf + total_chars_written, buf_len, "%s%s", str_arr[i], sep);
total_chars_written += chars_written;
buf_len = buf_len - chars_written;
/*
* see https://access.redhat.com/blogs/766093/posts/1976193 as to why
* the line below is added. TLDR: in a previous specification for UNIX
* snprintf can return a negative value if an output error was encountered.
* TODO:
* indicate to caller whether error resulted from
* snprintf error or from insufficient buffer size
*/
if (chars_written < 0) return chars_written;
if (buf_len <= 0) {
return buf_len - 1;
}
}
return total_chars_written;
}
/*
* Auto-allocates the right buffer size for use with join_strs. ie helper
* if a caller for join_strs cannot determine prior the size to use with join_strs
* Since buf allocated on heap, caller should make sure to free buf after use.
* Repeatedly calls join_str with a given buffer. Each time the call fails,
* join_strs_auto_alloc doubles the buffer size. If malloc fails, the return value
* is NULL, otherwise, it's the joined strings
*/
char *join_strs_auto_alloc(char **str_arr, int str_arr_len, const char *sep) {
int buf_len = sizeof(char) * 10;
while (true) {
char *buf = malloc(buf_len);
int chars_written = join_strs(buf, buf_len, str_arr, str_arr_len, sep);
if (chars_written >= 0) return buf;
free(buf);
buf_len = buf_len * 2;
buf = malloc(buf_len);
if (!buf) break;
}
return NULL;
}
int main(void) {
char *strs[] = {"abc", "def", "ghi", "jkl", "mnopq"};
char *merged = join_strs_auto_alloc(strs, 5, ", ");
printf("%s\n", merged); // abc, def, ghi, jkl, mnopq
free(merged);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment