Search code examples
cstringidiomsstring-building

Building a string in C


This seems like a question that would have been asked before, but I couldn't find it. (If you do, please point me there and close this as a duplicate.)

I have C code which works something like this:

printf("some characters");
for (; n >= 0; n--)
{
    printf(", %s", f(n, k));
}
printf("more characters");

for some variables n and k and function char* f(int n, int k) which are not important here. (n and k are not constant.) I would like to convert the code above to a function which returns a char* rather than simply using printf to display it. (It will ultimately be printed but this lets me do some refactoring and is of course easier to test that way.) Of course I could just create the strings and copy them over character-by-character but surely there is a better (cleaner, faster, more idiomatic) way of doing this.

In my particular application f is a very simple function, sort of a relative of itos, but which is not cacheable in any meaningful way due to k. But I welcome ideas which are good for that case as it may be useful to others in the future.


Solution

  • Step 1 would be to allocate a big enough buffer for the string. Then use sprintf to print into the buffer. The standard idiom is

    int index = sprintf( buffer, "some characters" );
    for (; n >= 0; n--)
    {
        index += sprintf( &buffer[index], ", %s", f(n, k) );
    }
    index += sprintf( &buffer[index], "more characters" );
    

    The sprintf function returns the length of the string that it wrote, which allows you to keep track of where you are in the buffer.


    You could also have the caller pass a buffer and size. In that case, it's best to use snprintf to avoid overrunning the buffer. So the function would look something like this

    char *create_string( char *buffer, int size, int n, int k )
    {
        ...
        index += snprintf( &buffer[index], size-index, ", %s", f(n, k) );
        ...
        return buffer;
    }
    

    where the size parameter is the size of the buffer.