4

I'm new to C.

I'm looking for an example where I could call a function to convert int to string. I found itoabut this is not part of standard C.

I also found sprintf(str, "%d", aInt); but the problem is that I don't know the size of the required str. Hence, how could I pass the right size for the output string

phuclv
  • 37,963
  • 15
  • 156
  • 475
user836026
  • 10,608
  • 15
  • 73
  • 129
  • 2
    Are you using gcc? `asprintf` is your friend if so. – Dan Mar 29 '16 at 03:35
  • 1
    If `aint` is a 32-bit (signed or unsigned) quantity, then 12 characters (10 digits, sign, trailing null) is sufficient. If it is a 64-bit signed quantity, then 21 characters is sufficient (19 digits, sign, trailing null); for an unsigned quantity without a sign, 21 is sufficient, but with a sign, you need 22. The usual trick is to allocate slightly more space than necessary. You could check the return value from `snprintf()` with a null string and zero length to find how much space you need. You could look at `asprintf()` as suggested, but it is fairly new and still has limited portability. – Jonathan Leffler Mar 29 '16 at 03:42

5 Answers5

5

There are optimal ways ways to appropriately size the array to account for variations in sizeof(int), but multiplying by 4 is sufficient for base 10. +1 is needed for the edge case of sizeof(int)==1.

int x; // assign a value to x
char buffer[sizeof(int) * 4 + 1];
sprintf(buffer, "%d", x);

If you need to return the pointer to the string from the function, you should allocate the buffer instead of using stack memory:

char* integer_to_string(int x)
{
    char* buffer = malloc(sizeof(char) * sizeof(int) * 4 + 1);
    if (buffer)
    {
         sprintf(buffer, "%d", x);
    }
    return buffer; // caller is expected to invoke free() on this buffer to release memory
}
selbie
  • 100,020
  • 15
  • 103
  • 173
  • Thanks... if I put the above code inside a function, what this funcation should return, char * or char[]? – user836026 Mar 29 '16 at 03:42
  • 2
    @user836026: you can't just return an array from a function. You need to pass an appropriately sized array into the function (easiest), or you need to do dynamic memory allocation (with `malloc()` et al — which is harder). If you pass the array in, also pass the size, and use `snprintf()` inside the function for safety. You should check for overflow errors if you do that, though — but then you should error check most functions. – Jonathan Leffler Mar 29 '16 at 03:45
  • 1
    @user836026 - What Jonathan just said. I updated my answer to show how to allocate an array with malloc. – selbie Mar 29 '16 at 03:46
  • @selbie Thank you. – user836026 Mar 29 '16 at 03:48
  • I should point out, in the theoretical case of `sizeof(int) == 1`, you would need to +1 the size of the allocation such that negative numbers can fit with a null terminator. In practice, `sizeof(int)` is always `> 1`, so it works out that it's not needed. – selbie Mar 29 '16 at 03:50
  • 1
    @selbie There are `sizeof(int)==1` systems around (they have minimum addressable unit of 16-bit or 32-bit). I guess the code should be `sizeof(int) * CHAR_BIT / 2`. – M.M Mar 29 '16 at 06:39
2

In portable C, it's easiest to use snprintf to calculate the size of the array required, and then sprintf for the actual conversion. For example:

char buffer[snprintf(NULL, 0, "%d", x) + 1];
sprintf(buffer, "%d", x);

It's worthwhile noting that this won't work prior to C99, and there's also a neater alternative which works prior to C99 and is type-generic for all integers. That's described in another answer to this question using the multiplication trick, however I noticed the trick proposed there isn't strictly portable either. In environments where CHAR_BIT isn't 8 (for example, some DSPs use 16- or 32- bit bytes), you'll need to change the multiplier.

I presented a similar trick in response to a different question. That code used CHAR_BIT to ensure portability, even when CHAR_BIT changes. It's presented as a macro, and so it's internally documenting; it tells you what the high-level description is, which a multiplication alone can't do.

#include <limits.h>
#include <stddef.h>
#include <stdio.h>

#define digit_count(num) (1                                /* sign            */ \
                        + sizeof (num) * CHAR_BIT / 3      /* digits          */ \
                        + (sizeof (num) * CHAR_BIT % 3 > 0)/* remaining digit */ \
                        + 1)                               /* NUL terminator  */

int main(void) {
    short short_number = -32767;
    int int_number = 32767;
    char short_buffer[digit_count(short_number)] = { 0 };
    char int_buffer[digit_count(int_number)];
    sprintf(short_buffer, "%d", short_number);
    sprintf(int_buffer, "%d", int_number);
}
autistic
  • 1
  • 3
  • 35
  • 80
  • +1 For suggesting the use of `snprintf` to calculate the array size. However, it deserves mention that this behavior doesn't seem to have been defined as such prior to C99. From `CONFORMING TO` of `man snprintf`: "SUSv2 and C99 contradict each other: when snprintf() is called with size=0 then SUSv2 stipulates an unspecified return value less than 1, while C99 allows str to be NULL in this case, 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." – Will Aug 21 '17 at 05:32
  • @Will Right you are, however just a tad nitpick, I'd assume since the SUS now defines C using a more current standard, that unless [SUSv2] or [C89] tags are used, C is C99 or C11. Additionally, the VLA won't work in C89... This might make a nice segue into the part following it. I'll edit now :) – autistic Aug 21 '17 at 10:32
  • @Will What do you think of this answer, now? – autistic Aug 21 '17 at 10:37
1

Use C99 snprintf(). It calculates how much space would be needed

int needed = snprintf(NULL, 0, "%s", value);
if (needed < 1) /* error */;
char *representation = malloc(needed + 1); // add 1 for '\0'
if (!representation) /* error */;
sprintf(representation, "%d", value);
// ... use representation ...
free(representation);
pmg
  • 106,608
  • 13
  • 126
  • 198
0

There is a way to do it without any functions, for example this(it can be a little primitive, but still):

char dec_rev[255];
dec_rev[0] = '\0';
int i = 0;

while (val != 0) {
    int temp = val % 10;
    dec_rev[i] = temp + '0';
    //printf("%c\n", dec_rev[i]);
    val /= 10;
    if (val == 0) {
        dec_rev[i + 1] = '\0';
        break;
    }
    i++;
}

char dec[255];
i = 0;
for (int j = strlen(dec_rev) - 1; j != -1; j--) {
    dec[i] = dec_rev[j];
    i++;
}

After all we get our int stored inside dec[255].

ibanezn04
  • 478
  • 5
  • 12
0

strange that this is not mentioned, but the size of the representation of an int in base 10 is ceil(log10(value)); (or log10 integer version if you want to write it)

thus ceil(log10(5)) => 1

and ceil(log10(555)) => 3

ceil(log10(1000000000)) => 9

obviously you need an extra room for the sign if you need it and another for the '\0'.

OznOg
  • 4,440
  • 2
  • 26
  • 35