The following C function:
int sprintf ( char * str, const char * format, ... );
writes formatted data to a string. The size of the array pa
Most people will tell you to use snprintf()
because it won't overrun the end of your buffer.
And this is OK advice. The usual "design pattern" is to declare a temporary fixed-size buffer that is larger than the string is ever likely to be and snprintf()
to that. If the string needs to be saved for a while you can then measure its length, malloc(3)
another, and strcpy(3)
the temporary buffer to the semi-permanent malloc()
buffer.
There is another way.
C99 specifies that if the buffer is NULL then no bytes are written but the actual length that would have been written is returned. This allows you to do a dummy first pass, malloc() a buffer, and then snprintf()
to that buffer. (In theory you could use plain sprintf()
, as the length is now known, but I wouldn't.)
Anyway, I'm not sure I would count on all this if my program had to run on every OS ever made in the past, but it's a reasonable pattern for most people to use these days.
First of all, use snprintf
instead of sprintf
. snprintf
takes an extra argument that is the maximum number of bytes to write (including trailing '\0'
). snprintf
then returns the number of bytes written, not including the trailing '\0'
. So you could allocate a buffer that you think will be large enough and try the call. If it hit the end of the buffer, free that buffer and make a new, larger one and try again. Rinse and repeat.
What you want is one of these two functions:
* snprintf
(http://libslack.org/manpages/snprintf.3.html). It takes the length of the output buffer as its second argument, and if the buffer is too small for the result it will return the number of characters needed, allowing you to reallocate a larger buffer.
* asprintf
. It takes a char **
argument and allocates enough memory to hold the output, as long as that much contiguous virtual memory is available. You have to call free
to remove it from memory if you're done with it before the program exits and may need the memory for something else.
I threw this together as an exercise for myself based on DigitalRoss' suggestion. Feel free to merge this with his answer if you have the rep (I don't).
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* createRandstr(void);
int main(void)
{
char* mystr;
char* randomString;
size_t len;
/* Makes a random string of A's */
randomString = createRandstr();
/* 1st pass gets needed size */
len = (size_t)snprintf(NULL, 0, "random string -->%s<--\n", randomString);
mystr = malloc(len);
/* Safely write to mystr with known length 'len' */
snprintf(mystr, len, "random string -->%s<--\n", randomString);
puts(mystr);
free(mystr);
free(randomString);
return 0;
}
char* createRandstr(void)
{
char* randstr;
size_t randlen;
unsigned int i;
srand((unsigned int)time((time_t*)NULL)); /* Seed rand() */
randlen = (size_t)rand() % 50; /* Limit to max of 49 chars */
randstr = malloc(randlen);
for (i=0; i < randlen; i++)
{
randstr[i] = 'A';
}
randstr[randlen - 1] = '\0';
return randstr;
}
You can use either snprintf or asprintf. snprintf involves checking the size and resizing if necessary, whereas asprintf simply allocates the correct size for you.