Reputation: 329
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
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
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
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
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