0

What is proper size of an char array (buffer) when i want to use sprintf function?

I dont know why this part of code is working if buffer can hold only 1 char? I put a lot more chars inside than 1.

/* sprintf example */
#include <stdio.h>

int main ()
{
    char buffer[1];
    int n, a=5, b=3;
    n = sprintf (buffer, "%d plus %d is %d", a, b, a+b);
    printf ("[%s] is a string %d chars long\n", buffer, n);
    return 0;
}

Results:

[5 plus 3 is 8] is a string 13 chars long
Neuron
  • 5,141
  • 5
  • 38
  • 59
susi33
  • 207
  • 1
  • 2
  • 4
  • If you're using C++ you can use the `std::string` and `std::stringstream` classes to accomplish this without needing to consider the memory requirements. If you must use `sprintf`, maybe [this question and its answers](http://stackoverflow.com/q/3919995/604687) will help you. – Ninjakannon Apr 18 '15 at 15:17
  • This program is out of contro! the sprintf function is writing data in an unassigned memory area! When you use sprintf, you must know, or you have to do the program able to compute, the dimension of the buffer to use. To avoid problem with memory boundary you may use the snprintf() function that takes care of the buffer dimension. – Sir Jo Black Apr 18 '15 at 15:25
  • "buffer can hold only 1 char" ... and that char can only be `'\0'` for buffer to be considered a *string*; anything else and you're invoking UB when using `buffer` as a string (`strlen(buffer)`, `strcat()`, ...) – pmg Jun 14 '21 at 15:58

3 Answers3

4

What is proper size of an char array (buffer) when i want to use sprintf function?

There isn't one.

If you can work out an upper bound from the format string and types of input, then you might use that. For example, a 32-bit int won't take up more than 11 characters to represent in decimal with an optional sign, so your particular example won't need more than 44 characters (unless I miscounted).

Otherwise, use something safer: std::stringstream in C++, or snprintf and care in C.

I don't know why this part of code is working if buffer can hold only 1 char?

It isn't. It's writing past the end of the buffer into some other memory.

Maybe that won't cause any visible errors; maybe it will corrupt some other variables; maybe it will cause a protection fault and end the program; maybe it will corrupt the stack frame and cause all kinds of havoc when the function tries to return; or maybe it will cause some other kind of undefined behaviour. But it's certainly not behaving correctly.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

In your code a buffer overflow occurred, there were no apparent consequences, but that doesn't mean it worked correctly, try using a memory debugger like valgrind and you will see what I mean.

You can't ensure that sprintf() will not overflow the buffer, that's why there is a snprintf() function to which you pass the size of the buffer.

Sample usage

char buffer[100];
int  result;
result = snprintf(buffer, sizeof(buffer), "%d plus %d is %d", a, b, a + b);
if (result >= sizeof(buffer))
 {
    fprintf(stderr, "The string does not fit `buffer'.\n");
 }
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
0

Assuming code must use sprintf() and not some other function:
pre-determine the worse case output size and add margin.

Unless there are major memory concerns, suggest a 2x buffer. Various locales can do interesting things like add ',' to integer output as in "123,456,789".

#include <stdio.h>
#include <limits.h>
#define INT_DECIMAL_SIZE(i) (sizeof(i)*CHAR_BIT/3 + 3)

#define format1 "%d plus %d is %d"
char buffer[(sizeof format1 * 3 * INT_DECIMAL_SIZE(int)) * 2];
int n = sprintf(buffer, format1, a, b, a + b);

A challenging example is when code tries sprintf(buf,"%Lf", some_long_double) as the output could be 1000s of characters should x == LDBL_MAX. About 5000 characters with binary128 as long double.

//                            -   123.............456   . 000000 \0
#define LDBL_DECIMAL_SIZE(i) (1 + 1 + LDBL_MAX_10_EXP + 1   + 6   1)
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256