2

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

3
  • 2
    Do you know the value at compile time? If yes, you can do char array[] = "2007";. If not, look at sprintf(). Commented Jan 3, 2010 at 21:26
  • 4
    'char array[4] ={ '2', '0', '0', '7', '\0' };' This is clearly wrong. You should use 'char array[5]={...". Commented Jan 3, 2010 at 22:35
  • Good catch. That's why I let the compiler do the counting by omitting the size entirely in expressions like this :-). Commented Jan 3, 2010 at 22:41

8 Answers 8

12

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);
Sign up to request clarification or add additional context in comments.

2 Comments

+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.
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)
4

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);

3 Comments

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).
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: That doesn't work in the 32 bit case though, because 2^32 and 2^31 have the same number of digits.
3

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.

5 Comments

Depending on the circumstances, you could be overallocating by a lot.
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.
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: 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)
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.
2
#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.

2 Comments

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.
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.
1

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

1 Comment

Note: that itoa is not part of the c standard.
1

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);

Comments

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

Comments

1

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

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.