user1423561
user1423561

Reputation: 329

Buffer size to convert double to char* in C

In order to convert a double (or float, int, long) to char* in C we can use

i) sprintf()

ii) functions like itoa(), ftoa()

But all these functions expect a buffer as a parameter. What should be size of the buffer in each case so that the maximum integer or the maximum precision float/double can be converted ?

Upvotes: 4

Views: 2403

Answers (4)

mafso
mafso

Reputation: 5543

snprintf can be used to determine the size, with a 0 argument as the size:

double x = 42;
const char fmt[] = "%f";
int size = snprintf(0, 0, fmt, x);
if(size < 0) { /* handle error */ }
char buf[size+1];
sprintf(buf, fmt, x);

The C standard requires snprintf with a 0 size argument to work. Note, though, that some older implementations don't conform (e.g. Glibc until version 2.0.6 returns -1 if the output was truncated instead of the number of characters that would have been written, according to the man page).

The error checking above may be useless, the only possible error which can occur is an encoding error.

You shouldn't change the locale between the snprintf and the sprintf call, the locale may affect the size. The sprintf can be replaced by a snprintf call again if intervening locale changes are a concern, but then you probably want to allocate the memory via malloc, and then realloc while necessary. [Thanks, Chux!]

Under Glibc, there is also asprintf which allocates the buffer itself. Don't forget to free it afterwards. [Thanks to Abligh!]

Upvotes: 3

chux
chux

Reputation: 154245

To convert a double to a string and using sprintf(), the buffer size needs depends on the format specifier.

Note that the buffers below are fixed at compile time, not VLA.

//       -   digits               .   000000 \0
char buf[1 + 1 + DBL_MAX_10_EXP + 1 + 6 + 1];
sprintf(buf, "%f", x);

//       -   digit.digits          e   -  xxxx \0
char buf[1 + 2 + DBL_DECIMAL_DIG + 1 + 1 + 4 + 1];
sprintf(buf, "%.*e", DBL_DECIMAL_DIG, x);

// Others: %0.100f %a %*.*E etc.

But printf() functions consider their locale so additional characters could show up. Suggest oversizing buffer to 2x the expected size, using snprintf() and then sleeping well at night.

//       -   digit.digits          e   -  xxxx \0
char buf[(1 + 2 + DBL_DECIMAL_DIG + 1 + 1 + 4 + 1)*2];
int len = snprintf(buf, "%.*e", DBL_DECIMAL_DIG, x);
if (len < 0 || len >= sizeof buf) {
  Handle_Insanity();
}

Ref: Printf width specifier to maintain precision of floating-point value

Upvotes: 1

user1196549
user1196549

Reputation:

Unfortunately, there is no way to limit the length with the %f specifier, as the length parameter is a minimum, not a maximum. So large values take as many characters as their exponent, not counting the decimals.

For example, "%f.10", 1.e20f yields 100000002004087730000.0000000000.

In this respect, sprintf is extremely unsafe (should be banned), prefer snprintf.

Upvotes: 1

DrKoch
DrKoch

Reputation: 9782

Make the buffer just large enough. A double has about 15 places plus exponent and signs. A buffer char buffer[25] should do.

Upvotes: 1

Related Questions