Reputation: 415
I'm wondering what the proper way is too convert a double of unknown value size to a string without allocating too much memory. Is there any way to figure out the count of digits in a double? I don't want to allocate too much or too less memory.
Upvotes: 1
Views: 1353
Reputation: 154245
Proper way to convert a double to string without allocating more memory than required?
Use snprintf()
to determine the character count need.
double value = foo();
int size = snprintf(NULL, 0, some_format, value);
if (size < 0) Handle_encoding_error(); // This is very rare
else {
char *buffer = malloc(size + 1u);
if (buffer == NULL) Handle_OOM_error(); // This is also rare
else {
snprintf(buffer, 0, some_format, value);
puts(buffer);
free(buffer);
}
}
What format to use depends on coding goals. "%f"
often results in many uninformative digits for large values and "0.00000"
for about half of all double
as many are wee values less than 0.0000005 in magnitude.
A good way to print a double
with significant digits employ exponential notation. What is great about using exponential notation is not only is the double
fully expressed, it maximum string size need can be pre-calculated (about 28) and is not excessive.
By printing with exponential notation and precision of DBL_DECIMAL_DIG - 1
, code does not need more digits to "round-trip" the string back to the same double
with strtod()
or sscanf()
.
"%a" // Hexadecimal signicand
"%.*e" // Decimal
int size = snprintf(NULL, 0, "%a", value);
// or
int size = snprintf(NULL, 0, "%.*e", DBL_DECIMAL_DIG-1, value);
// or directly with minimal extra space
// - d . dddddd e - expo \0
#define N (1 + 1 + 1 + (DBL_DECIMAL_DIG - 1) + 1 + 1 + 6 + 1)
char buf[N];
snprintf(buf, sizeof buf, "%.*e", DBL_DECIMAL_DIG-1, value);
See Printf width specifier to maintain precision of floating-point value
Upvotes: 1
Reputation: 41036
You can use NULL
as the first argument of snprintf
to get the size:
C99 allows str to be NULL and gives the return value (as always) as the number of characters that would have been written in case the output string has been large enough.
And then malloc
:
int main(void)
{
double num = 3.14;
size_t len;
char *str;
len = (size_t)snprintf(NULL, 0, "%f", num) + 1;
str = malloc(len);
snprintf(str, len, "%f", num);
puts(str);
free(str);
return 0;
}
Upvotes: 6
Reputation: 13590
Here you have a basic example of how to use snprintf
when you only want to
know the length of the representation:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main(void)
{
int size = snprintf(NULL, 0, "%.15lf", M_PI);
char *pi = malloc(size + 1);
sprintf(pi, "%.15lf", M_PI);
printf("PI: '%s'\n", pi);
free(pi);
return 0;
}
Upvotes: 5