Using the standard C library, I want to repeatedly concatenate onto a fixed size string. Despite it's promising name, the semantics of strncat do not appear suited to doing this, and the return value provides no new information. strncpy also requires a strlen to update the position. The reason I used snprintf (C99) in the code below is that it returns the number of characters written, which I can subtract from future calls. I've written a helper struct,#include <stdlib.h> /* EXIT_SUCCESS */#include <stdio.h>  /* *printf */#include <string.h> /* strlen */struct Supercat {    char *print, *cursor;    size_t left;    int is_truncated;};/** Initialises {cat} to hold the string {print}, size {print_size}. It stores the empty string in print. */static void supercat_init(struct Supercat *const cat, char *const print,    const size_t print_size) {    cat->print        = cat->cursor = print;    cat->left         = print_size;    cat->is_truncated = 0;    print[0] = '\0';}/** Adds {append} to the string specified when \see{supercat_init} was called. If {append} is too big for the size, it truncates the string and sets {cat.is_truncated}. */static void supercat(struct Supercat *const cat, const char *const append) {    size_t size_took;    int took;    if(cat->is_truncated) return;    took = snprintf(cat->cursor, cat->left, %s, append);    if(took < 0)  { cat->is_truncated = -1; return; }    if(took == 0) { return; }    if((size_took = took) >= cat->left) {        cat->is_truncated = -1, size_took = cat->left - 1;    }    cat->cursor += size_took, cat->left -= size_took;}static const char *const start_str     = [ ;static const char *const end_str       =  ];static const char *const alter_end_str = ...];static const char *const sep_str       = , ;static const char *const null_str      = Null;int main(int argc, char **argv) {    static char buffer[80];    struct Supercat cat;    int i;    /* want to terminate before the end; always have space for alter_end_str */    supercat_init(&cat, buffer, sizeof buffer - strlen(alter_end_str));    if(!argc) {        supercat(&cat, null_str);    } else {        supercat(&cat, start_str);        for(i = 0; i < argc; i++) {            if(i) supercat(&cat, sep_str);            supercat(&cat, argv[i]);            if(cat.is_truncated) break;        }        /* we are guaranteed to have enough room */        sprintf(cat.cursor, %s, cat.is_truncated ? alter_end_str : end_str);    }    printf(Arguments: %s.\n, cat.print);    return EXIT_SUCCESS;}The string now will go up to 79 characters and refuse to write any more,Thor:Supercat neil$ bin/Supercat Arguments: [ bin/Supercat ].Thor:Supercat neil$ bin/Supercat saves the day!Arguments: [ bin/Supercat, saves, the, day! ].Thor:Supercat neil$ bin/Supercat where are you? we need you to rescue us from the burning building.Arguments: [ bin/Supercat, where, are, you?, we, need, you, to, rescue, us, from, the,...].Thor:Supercat neil$ bin/Supercat where are you? we need you to rescue us from this burning building.Arguments: [ bin/Supercat, where, are, you?, we, need, you, to, rescue, us, from, this...].Thor:Supercat neil$ bin/Supercat where are you? we need you to rescue us from danger.Arguments: [ bin/Supercat, where, are, you?, we, need, you, to, rescue, us, from, dang...].Using a temporary structure is a pain, but it seems to me like writing something like, if(strlen(strncat(cat, argv[i], sizeof cat - strlen(cat))) >= sizeof buffer) break;, would be inefficient on large strings because traversal the string 3 times (I count) to write one value. On the other hand, snprintf is overkill with a constant format string.
Concatenating strings into a fixed-size char array in C
performance;c;strings;library