tags:

views:

115

answers:

4

When converting an int like so:

char a[256];
sprintf(a, "%d", 132);

what's the best way to determine how large a should be? I assume manually setting it is fine (as I've seen it used everywhere), but how large should it be? What's the largest int value possible on a 32 bit system, and is there some tricky way of determining that on the fly?

A: 

First off, sprintf is the devil. If anything, use snprintf, or else you risk trashing memory and crashing your app.

As for the buffer size, it's like all other buffers - as small as possible, as big as necessary. In your case, you have a signed integer, so take the largest possible size, and feel free to add a little bit of safety padding. There is no "standard size".

It's also not dependent on what system you're running on. If you define the buffer on the stack (like in your example), it depends on the size of the stack. If you created the thread yourself, then you determined the stack size yourself, so you know the limits. If you are going to expect recursion or a deep stack trace, then you need to extra careful as well.

EboMike
Thank you. snprintf it is then.
Dominic Bou-Samra
There is no danger to using `sprintf` with a correctly sized buffer. For numeric output, sizing the buffer is easy. See Steve's answer.
R..
+1  A: 

The max possible number of bits in an int is CHAR_BIT * sizeof(int), and a decimal digit is "worth" at least 3 bits, so a loose upper bound on the space required for an arbitrary int is (CHAR_BIT * sizeof(int) / 3) + 3. That +3 is one for the fact that we rounded down when dividing, one for the sign, one for the nul terminator.

If by "on a 32 bit system" you mean that you know int is 32 bits, then you need 12 bytes. 10 for the digits, one for the sign, one for the nul terminator.

In your specific case, where the int to be converted is 132, you need 4 bytes. Badum, tish.

It's a bit overkill for such a simple case as this, but for difficult cases, in C99 you could just call snprintf to get the size, then malloc that much.

Static allocation is for microcontrollers ;-) [Edit: this was intended as a feeble joke, implying that any avoidance of malloc is tantamount to static allocation. In truth, where fixed-size buffers can be used with a reasonable bound, they are the simpler option on any C implementation].

Steve Jessop
Using `malloc` for this is ridiculous. It overcomplicates your code by adding a failure case you have to check -- and what do you do if it fails?!? Simply use a correctly sized buffer like you explained how to do.
R..
@R. Very well, I will expand upon my existing, "a bit overkill for such a simple case as this".
Steve Jessop
A: 

Its good that you are worried about buffer size. To apply that thought in code, I would use snprintf

snprintf( a, 256, "%d", 132 );

or

snprintf( a, sizeof( a ), "%d", 132 );  // when a is array, not pointer
ArunSaha
`snprintf` only solves half the problem. If you're not sure your buffer is big enough, you need to use `snprintf` to test the necessary size or make sure your code does not have bugs when the output gets truncated. Steve's answer is a lot better.
R..
A: 

Some here are arguing that this approach is overkill, and for converting ints to strings I might be more inclined to agree. But when a reasonable bound for string size cannot be found, I have seen this approach used and have used it myself.

int size = snprintf(NULL, 0, "%d", 132);
char * a = malloc(size + 1);
sprintf(a, "%d", 132);

I'll break down what's going on here.

  1. On the first line, we want to determine how many characters we need. The first 2 arguments to snprintf tell it that I want to write 0 characters of the result to NULL. When we do this, snprintf won't actually write any characters anywhere, it will simply return the number of characters that would have been written. This is what we wanted.
  2. On the second line, we are dynamically allocating memory to a char pointer. Make sure and add 1 to the required size (for the trailing \0 terminating character).
  3. Now that there is enough memory allocated to the char pointer, we can safely use sprintf to write the integer to the char pointer.

Of course you can make it more concise if you want.

char * a = malloc(snprintf(NULL, 0, "%d", 132) + 1);
sprintf(a, "%d", 132);

Unless this is a "quick and dirty" program, you always want to make sure to free the memory you called with malloc. This is where the dynamic approach gets complicated with C. However, IMHO, if you don't want to be allocating huge char pointers when most of the time you will only be using a very small portion of them, then I don't think this is bad approach.

Daniel Standage