Convert integer into an array - c

I am working on a C program, and I am coming across a small problem. I don't know how to convert an integer (say 2007) into a char array. Is there a function in the C libraries to do that for me?
To clarify, I'd like to take 2007 and store it in some char array[4] ={ '2', '0', '0', '7', '\0' };
I was thinking something like sprintf, but I'm not sure. Anyways, any help/hints would be appreciated.
Thanks,
Michael

You can do that with sprintf, or more safely snprintf.
Here's a contrived example:
#include <stdio.h>
#define MAX_LEN 5
char str[MAX_LEN];
snprintf(str, MAX_LEN, "%d", 2007);

Use snprintf() and be sure allocate the proper amount of space to hold numbers up to 2^(sizeof(int)*CHAR_BIT). On a 64-bit machine, that will be 20 digit characters, plus 1 for the NULL terminator.
#include <stdio.h>
#define MAX_DIGITS 20
int n = 2007;
char str[MAX_DIGITS+1];
snprintf(str, MAX_DIGITS+1, "%d", n);

As others have said, you should look at sprintf() or snprintf(). Assuming you are trying to convert an integral type T to such an array, the interesting bit is to figure out the size of the buffer for the array.
First, the number of digits in a number's decimal representation is ⌊log10n+1⌋. The maximum possible value of an unsigned integral type T can be represented in nbits = CHAR_BIT*sizeof(T) binary bits, which will need ⌊log102nbits⌋+1 decimal digits.
log102nbits = nbits×log102 = nbits×log(2)/log(10).
28/93 is a very good1 rational approximation of log(2)/log(10) (0.30107526881720431 vs 0.30102999566398114).
So, using the above, we get our expression for the number of digits:
CHAR_BIT * sizeof(T) * 28 / 93 + 1
For signed numbers, we need to add 1 more for the - sign, and we need to add 1 for the terminating 0. So we get:
#include <limits.h>
/* Figure out the maximum number of characters including the
terminating 0 to represent the numbers in integral type T */
#define SZ(T) (CHAR_BIT * sizeof(T) * 28 / 93 + 3)
So we can do:
char array[SZ(int)];
sprintf(array, "%d", n);
And we are sure that array has enough space. We don't have to worry about snprintf() or malloc()/realloc() and free() combination either.
Here is a complete program using the above:
#include <stdio.h>
#include <limits.h>
/* Figure out the maximum number of characters including the
terminating 0 to represent the numbers in integral type T */
#define SZ(T) (CHAR_BIT * sizeof(T) * 28 / 93 + 3)
#define PRINT(x) do \
{ \
printf("%s: %lu\n", #x, (unsigned long)SZ(x)); \
} while (0)
int main(void)
{
PRINT(int);
PRINT(long);
PRINT(size_t);
return 0;
}
1or good enough for this purpose.

#include <stdio.h>
char array[5];
sprintf(array, "%d", 2007);
...done.
Note that sprintf is not overflow safe, so if you have a number of 5 or more digits you'll have a problem. Note also that the converted number will be followed by a terminating \0.

The classic way is itoa. Or you can use snprintf to get more control.

There is a nonstandard, but well-supported as I undertand it, function itoa - the opposite of atoi.
Example:
char *a = malloc(10 * sizeof(char));
itoa(2007, a, 2007);
sprintf also works:
char *a = malloc(10 * sizeof(char));
sprintf(a, "%d", 2007);

int n = 2007;
char a[100];
sprintf( a, "%d", n );

Use snprintf:
// value is int;
// buf is char *;
// length is space available in buf
snprintf(buf, length, "%d", value)
snprintf has the advantage of being standard and giving your more flexibility over the formatting as well as being safe.
You could also use itoa but be warned that it is not part of the standard. Most implementations have it though.
Usage:
// value is int;
// buf is char *;
itoa(value, buf, 10);
An interesting question is: how much space do you allocate for buf? We note the following. With sizeof(int) bytes per int and eight bits per byte, the maximum value is approximately 2^(CHAR_BIT * sizeof(int) - 1) (-1 is for sign bit). Therefore we need space to hold
floor(log_10(2^(CHAR_BIT * sizeof(int) - 1)) + 1
digits. But don't forget the sign and null terminator! So the maximum length of an integer representable here is
floor(log_10(2^(CHAR_BIT * sizeof(int) - 1)) + 3.
Of course, this could be wasting space if our values are small. To find out how much space a specific value needs:
floor(log_10(abs(value))) + 1 + (value < 0 ? 1 : 0) + 1

Related

Get size of char buffer for sprintf handling longs C

I am quite new to C and occurred a question, when dealing with long ints/char* in C. I want to store a long in a char*, but I am not sure, how I should manage the size of my buffer to fit any long given.
Thats what I want:
char buffer[LONG_SIZE]; // what should LONG_SIZE be to fit any long, not depending on the OS?
sprintf(buffer, "%ld", some_long);
I need to use C not C++. Is there any solution to this, if I don't want to use magic-numbers?
if I don't want to use magic-numbers
Using snprintf() with a 0-length buffer will return the number of chars needed to hold the result (Minus the trailing 0). You can then allocate enough space to hold the string on demand:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(void) {
long some_long = LONG_MAX - 5;
// Real code should include error checking and handling.
int len = snprintf(NULL, 0, "%ld", some_long);
char *buffer = malloc(len + 1);
snprintf(buffer, len + 1, "%ld", some_long);
printf("%s takes %d chars\n", buffer, len);
free(buffer);
}
There's also asprintf(), available in Linux glibc and some BSDs, that allocates the result string for you, with a more convenient (But less portable) interface than the above.
Allocating the needed space on demand instead of using a fixed size has some benefits; it'll continue to work without further adjustment if you change the format string at some point in the future, for example.
Even if you stick with a fixed length buffer, I recommend using snprintf() over sprintf() to ensure you won't somehow overwrite the buffer.
It is probably more correct to use snprintf to compute the necessary size, but it seems like this should work:
char buf[ sizeof(long) * CHAR_BIT ];
The number of bits in a long is sizeof long * CHAR_BIT. (CHAR_BIT is defined in <limits.h>.) This can represent at most a signed number of magnitude 2sizeof long * CHAR_BIT - 1.
Such a number can have at most floor(log102sizeof long * CHAR_BIT - 1)+1 decimal digits. This is floor((sizeof long * CHAR_BIT - 1) * log102) + 1. log102 is less than .302, so (sizeof long * CHAR_BIT - 1) * 302 / 1000 + 1 bytes is enough for the digits.
Add one for a sign and one for a terminating null character, and char[(sizeof long * CHAR_BIT - 1) * 302 / 1000 + 3] suffices for the buffer.

8 Byte Number as Hex in C

I have given a number, for example n = 10, and I want to calculate its length in hex with big endian and save it in a 8 byte char pointer. In this example I would like to get the following string:
"\x00\x00\x00\x00\x00\x00\x00\x50".
How do I do that automatically in C with for example sprintf?
I am not even able to get "\x50" in a char pointer:
char tmp[1];
sprintf(tmp, "\x%x", 50); // version 1
sprintf(tmp, "\\x%x", 50); // version 2
Version 1 and 2 don't work.
I have given a number, for example n = 10, and I want to calculate its length in hex
Repeatedly divide by 16 to find the number of hexadecimal digits. A do ... while insures the result is 1 when n==0.
int hex_length = 0;
do {
hex_length++;
} while (number /= 16);
save it in a 8 byte char pointer.
C cannot force your system to use 8-byte pointer. So if you system uses 4 byte char pointer, we are out of luck. Let us assume OP's system uses 8-byte pointer. Yet integers may be assigned to pointers. This may or may not result in valid pointer.
assert(sizeof (char*) == 8);
char *char_pointer = n;
printf("%p\n", (void *) char_pointer);
In this example I would like to get the following string: "\x00\x00\x00\x00\x00\x00\x00\x50".
In C, a string includes the various characters up to an including a null character. "\x00\x00\x00\x00\x00\x00\x00\x50" is not a valid C string, yet is a valid string literal. Code cannot construct string literals at run time, that is a part of source code. Further the relationship between n==10 and "\x00...\x00\x50" is unclear. Instead perhaps the goal is to store n into a 8-byte array (big endian).
char buf[8];
for (int i=8; i>=0; i--) {
buf[i] = (char) n;
n /= 256;
}
OP's code certainly will fail as it attempts to store a string which is too small. Further "\x%x" is not valid code as \x begins an invalid escape sequence.
char tmp[1];
sprintf(tmp, "\x%x", 50); // version 1
Just do:
int i;
...
int length = round(ceil(log(i) / log(16)));
This will give you (in length) the number of hexadecimal digits needed to represent i (without 0x of course).
log(i) / log(base) is the log-base of i. The log16 of i gives you the exponent.
To make clear what we're doing here: When rising 16 to the power of the found exponent, we get back i: 16^log16(i) = i.
By rounding up this exponent using ceil(), you get the number of digits.

Buffer size for converting unsigned long to string

In reference to question and the answer
here: Can I use this method so that the solution will be platform independent.
char *buff = (char*) malloc(sizeof(unsigned long)*8);
sprintf(buff, "%lu", unsigned_long_variable);
Here I am getting the value of buffer length as it will similar to unsigned long variable. Is this approach correct?
Don't even try to calculate the buffer size.
Start with snprintf, which will tell you safely how many characters are needed. Then you know how many bytes to allocate to print safely.
Since this is a few lines of code that you don't want to repeat again and again, write a function malloc_printf that does exactly what you want: In that function, call snprintf with a NULL destination, then malloc the buffer, sprintf into the malloc buffer, and return it. To make it faster and to often avoid two snprintf and sprintf calls, write into a buffer of 256 chars first which is often enough.
So your final code would be
char* buff = malloc_printf ("%lu", unsigned_long_variable);
Also does quick, safe and easy string concatenation using the format %s%s, for example.
You want to know how many characters are needed to represent the largest possible unsigned long. Correct?
To that end, you are trying to calculate the largest possible unsigned long:
sizeof(unsigned long)*8
That is faulty in several ways. For one, sizeof returns multiples of char, which need not be 8 bit. You should multiply with CHAR_BIT (from <limits.h>) instead. But even that is not necessary, because that very same header already does provide the largest possible value -- UCHAR_MAX.
Then you're making a mistake: Your calculation gives the size of the integer representation of unsigned long in bits. What you want is the size of the string representation in characters. This can be achieved with the log10() function (from <math.h>):
log10( UCHAR_MAX )
This will give you a double value that indicates the number of (decimal) digits in UCHAR_MAX. It will be a fraction, which you need to round up (1) (ceil() does this for you).
Thus:
#include <math.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
char * buff = malloc( ceil( log10( UCHAR_MAX ) ) + 1 );
//...
}
All in all, this is quite dodgy (I made two mistakes while writing this out, shame on me -- if you make mistakes when using this, shame on you). And it requires the use of the math library for something that snprintf( NULL, ... ) can do for you more easily, as indicated by the Q&A you linked to.
(1): log10( 9999 ) gives 3.9999565... for the four-digit number.
The C standard doesn't put an upper limit to the number of bits per char.
If someone constructs a C compiler that uses for example 2000 bits per char the output can overflow the buffer.
Instead of 8 you should use CHAR_BIT from limits.h.
Also, note that you need (slighly less than) 1 char per 3 bits and you need 1 byte for the string terminator.
So, something like this:
#include <limit.h>
char *buff = malloc(1 + (sizeof(unsigned long) * CHAR_BIT + 2) / 3);
sprintf(buff, "%lu", unsigned_long_variable);
No, this is not the right way to calculate the buffer size.
E.g. for 4 byte unsigned longs you have values up to 2^32-1
which means 10 decimal digits. So your buffer needs 11 chars.
You are allocating 4 * 8 = 32.
The correct formula is
ceil(log10(2^(sizeof(unsigned long) * CHAR_BIT) - 1)) + 1
(log10 denotes the decimal logarithm here)
A good (safe) estimation is:
(sizeof(unsigned long) * CHAR_BIT + 2) / 3 + 1
because log10(2) is less than 0.33.
Short answer:
#define INTEGER_STRING_SIZE(t) (sizeof (t) * CHAR_BIT / 3 + 3)
unsigned long x;
char buf[INTEGER_STRING_SIZE(x)];
int len = snprintf(buf, sizeof buf, "%lu", x);
if (len < 0 || len >= sizeof buf) Handle_UnexpectedOutput();
OP's use of sizeof(unsigned long)*8 is weak. On systems where CHAR_BIT (the # of bits per char) is large (it must be at least 8), sizeof(unsigned long) could be 1. 1*8 char is certainly too small for 4294967295 (the minimum value for ULONG_MAX).
Concerning: sprintf()/snprintf() Given locale issues, in theory, code may print additional characters like 4,294,967,295 and so exceed the anticipated buffer. Unless very tight memory constraints occur, recommend a 2x anticipated sized buffer.
char buf[ULONG_STRING_SIZE * 2]; // 2x
int len = snprintf(buf, sizeof buf, "%lu", x);
The expected maximum string width of printing some unsigned integer is ceil(log10(unsigned_MAX)) + 1. In the case of of unsigned long, the value of ULONG_MAX certainly does not exceed pow(2,sizeof (unsigned long) * CHAR_BIT) - 1 so code could use:
#define LOG10_2 0.30102999566398119521373889472449
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * LOG10_2 + 2)
// For greater portability, should use integer math.
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT / 3 + 2)
// or more precisely
#define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * 28/93 + 2)
The short answer used +3 in case a signed` integer was specified.

Whats the easiest way to convert a long in C to a char*?

What is the clean way to do that in C?
wchar_t* ltostr(long value) {
int size = string_size_of_long(value);
wchar_t *wchar_copy = malloc(value * sizeof(wchar_t));
swprintf(wchar_copy, size, L"%li", self);
return wchar_copy;
}
The solutions I came up so far are all rather ugly, especially allocate_properly_size_whar_t uses double float base math.
A long won't have more than 64 digits on any platform (actually less than that, but I'm too lazy to figure out what the actual minimum is now). So just print to a fixed-size buffer, then use wcsdup rather than trying to calculate the length ahead of time.
wchar_t* ltostr(long value) {
wchar_t buffer[ 64 ] = { 0 };
swprintf(buffer, sizeof(buffer), L"%li", value);
return wcsdup(buffer);
}
If you want a char*, it's trivial to translate the above:
char* ltostr(long value) {
char buffer[ 64 ] = { 0 };
snprintf(buffer, sizeof(buffer), "%li", value);
return strdup(buffer);
}
This will be faster and less error-prone than calling snprintf twice, at the cost of a trivial amount of stack space.
int charsRequired = snprintf(NULL, 0, "%ld", value) + 1;
char *long_str_buffer = malloc(charsRequired);
snprintf(long_str_buffer, charsRequired, "%ld", value);
The maximum number of digits is given by ceil(log10(LONG_MAX)). You can precompute this value for the most common ranges of long using the preprocessor:
#include <limits.h>
#if LONG_MAX < 1u << 31
#define LONG_MAX_DIGITS 10
#elif LONG_MAX < 1u << 63
#define LONG_MAX_DIGITS 19
#elif LONG_MAX < 1u << 127
#define LONG_MAX_DIGITS 39
#else
#error "unsupported LONG_MAX"
#endif
Now, you can use
wchar_t buffer[LONG_MAX_DIGITS + 2];
int len = swprintf(buffer, sizeof buffer / sizeof *buffer, L"%li", -42l);
to get a stack-allocated wide-character string. For a heap-allocated string, use wcsdup() if available or a combination of malloc() and memcpy() otherwise.
Many people would recommend you avoid this approach, because it's not apparent that the user of your function will have to call free at some point. Usual approach is to write into a supplied buffer.
Since you receive a long, you know it's range will be in –2,147,483,648 to 2,147,483,647 and since swprintf() uses locale ("C") by default (you control that part), you only need 11 characters. This saves you from string_size_of_long().
You could either (for locale C):
wchar_t* ltostr(long value) {
wchar_t *wchar_copy = malloc(12 * sizeof(wchar_t));
swprintf(wchar_copy, 12, L"%li", value);
return wchar_copy;
}
Or more general but less portable, you could use _scwprintf to get the length of the string required (but then it's similar to your original solution).
PS: I'd simplify the memory allocation and freeing more than this "tool-box" function.
You can use the preprocessor to calculate an upper bound on the number of chars required to hold the text form of an integer type. The following works for signed and unsigned types (eg MAX_SIZE(int)) and leaves room for the terminating \0 and possible minus sign.
#define MAX_SIZE(type) ((CHAR_BIT * sizeof(type)) / 3 + 2)

What is the minimum buffer size for sprintf with %g?

The problem is to statically allocate a buffer large enough to fit a printed double, formatted with %g at maximum precision. This seems like a simple enough task, bu I'm having trouble. The best I have come up with (assuming the number to be printed is x) is
char buf[1 + DBL_DIG + DBL_DIG + 1 + 1 + 1 + DBL_DIG + 1];
int len = sprintf(buf, "%.*g", DBL_DIG, x);
The DBL_DIG macro is from float.h, and apparently it is supposed to indicate the maximum precision for the type double. We need:
1 byte for a negative sign
enough bytes to capture the significant digits
at most one 'separator' char (comma, etc.) per digit
1 byte for a decimal point
1 byte for 'e'
1 byte for the sign on the exponent
some bytes for the exponent
1 byte for the trailing null written by sprintf.
I'm using the number of significant digits as an upper bound on the number of digits in the exponent. Have I made any errors? Is there a better solution? Should I just allocate 64, 128, or 256 bytes and hope for the best?
You cannot pre-calculate the size at compile time. The %g formatter takes the locale into account (for the 1000's separator etc.)
See http://linux.die.net/man/3/sprintf for a description on how to calculate the size safely.
Use snprintf() to find out how many characters you need:
#include <float.h> /* DBL_DIG */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
double x = rand() / (double)RAND_MAX;
char find_len[1];
int need_len;
char *buf;
need_len = snprintf(find_len, 1, "%.*g", DBL_DIG, x);
buf = malloc(need_len + 1);
if (buf) {
int used = sprintf(buf, "%.*g", DBL_DIG, x);
printf("need: %d; buf:[%s]; used:%d\n", need_len, buf, used);
free(buf);
}
return 0;
}
You need a C99 compiler for snprintf().
snprintf() was defined by the C99 standard. A C89 implementation is not required to have snprintf() defined, and if it has as an extension, it is not required to "work" as described by the C99 Standard.
Instead of using sprintf, you could use asprintf. This allocates a buffer of the correct size to fit your string.
Two things: %g does not show all of the representable digits, %g shows a nice-for-humans rounded result. You can specify the precision using %f or %e if you would like a different result.
Never use sprintf() rather than using snprintf(). In your case:
int len = snprintf(buf, dimensionof(buf), "%.*f", DBL_DIG, x);
Should I just round up to 64, 128, or
256 and hope for the best?
Yes, just do that -.-

Resources