Last active
April 23, 2020 08:14
-
-
Save bnm3k/1766a650305b943782da9592d0c7d8b8 to your computer and use it in GitHub Desktop.
Procedure demonstrating joining of strings in C using snprintf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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