tags:

views:

187

answers:

8

Hi,

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

+1  A: 

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
Jason
You're assuming that `CHAR_BIT` is 8, also you need one extra byte for the terminating 0. See my answer for an expression that's a compile-time constant, allowing automatic variable creation of the right size.
Alok
+1  A: 

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

bmargulies
Note: that itoa is not part of the c standard.
quinmars
+11  A: 

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);
tgamblin
+1. It's often a good idea to use `sizeof(str)` as the second argument to `snprintf`, though your use of a macro here works equally well, in case the size of the buffer ever changes.
Adam Rosenfield
It's a nice trick if you remember that it only works with statically sized char arrays. It won't compile in C99 if str is dynamically allocated, and it will blow up most of the time if str is declared as a char* and malloc'd (though notably not in this example on a 64-bit architecture :-P)
tgamblin
+1  A: 

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);
Lucas Jones
+2  A: 
#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.

Carl Smotricz
If the maximum number of digits is fixed it's safer to use `%4d` as the formatting field (of course you can change 4 to whatever is the maximum). That prevents the overflow issue.
Martinho Fernandes
No, that doesn't make things safer. sprintf will happily overflow the width you give it. From the manpage: "In no case does a non-existent or small field width cause truncation of a field". If you want safer, use snprintf.
tgamblin
+1  A: 
int n = 2007;
char a[100];
sprintf( a, "%d", n );
anon
+4  A: 

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);
Adam
The worst case is actually negative numbers, because of the additional character taken by the `-`. So the proper amount of space should be "to hold numbers down to -1 * 2^(sizeof(int) * `CHAR_BIT` - 1)", which can be approximated to `((sizeof(int) * CHAR_BIT - 1) / 3) + 3` (including the terminating nul character).
caf
Good point about CHAR_BIT. However, the answer still comes out the same because you're subtracting 1 from the exponent to account for the sign bit. 2^64 = 18,446,744,073,709,551,616 which is 20 characters (not counting the commas). -1*(2^63) = -9,223,372,036,854,775,808 which is also 20 characters.
Adam
Adam: That doesn't work in the 32 bit case though, because 2^32 and 2^31 have the same number of digits.
caf
Good point. I'm so used to thinking in 64-bit now...
Adam
+2  A: 
Alok
Depending on the circumstances, you could be overallocating by a lot.
Jason
Yes, I agree. If memory is an issue, the best solution would be to dynamically allocate the buffer, in which case your solution works (although both your and my solutions are basically the same anyway). My solution uses more memory than needed because it calculates the size for the worst-case scenario, but the advantage is that `SZ` above is a compile-time constant, allowing array creation in ANSI C89.
Alok
That's a pretty big hammer for such a tiny nail. I wouldn't worry about wasting memory and just use a maximum size of 22.
Adam Rosenfield
@Adam: True. But the "hammer" is in the calculation of the expression, which needs to be done only once (by a human that is). Similarly, the "hammer" while compiling is in preprocessor. When the size of an `int` changes to 16 sometime in future(!), 22 isn't going to be big enough :-) (tongue-in-cheek)
Alok
640 KB....I mean 64 bits should be enough for anyone!
Adam Rosenfield
The number of digits in a number's decimal representation is floor(log10(n)+1). For example, `floor(log10(10)+1) = 2` and `floor(log10(123456)+1) = 6`.
Adam
You're right. Fixing.
Alok