How can I convert an int to a string in C?
Asked Answered
M

11

388

How do you convert an int (integer) to a string?

I'm trying to make a function that converts the data of a struct into a string to save it in a file.

Manana answered 24/11, 2011 at 13:19 Comment(2)
possible duplicate of Where is the itoa function in Linux?Circulate
possible duplicate of Converting int to string in cMozarab
V
172

As pointed out in a comment, itoa() is not a standard, so better use the sprintf() approach suggested in the rival answer!


You can use the itoa() function to convert your integer value to a string.

Here is an example:

int num = 321;
char snum[5];

// Convert 123 to string [buf]
itoa(num, snum, 10);

// Print our string
printf("%s\n", snum);

If you want to output your structure into a file there isn't any need to convert any value beforehand. You can just use the printf format specification to indicate how to output your values and use any of the operators from printf family to output your data.

Vivle answered 24/11, 2011 at 13:22 Comment(7)
itoa is not standard - see e.g. #190729Circulate
@SeanRamey This itoa() suffers the same buffer overflow potential as gets().Lacey
itoa is not available in C (C99 at least). it is more available in C++Woodworm
How to get this without sprintf or itoa? Possibly while writing a custom standard library?Statampere
why did you pass argument as 10?Gheber
Add #include <stdlib.h>.Firecure
To be clear @AlexanderGalkin, the comment incorrectly says that you are converting "123 to string", whereas you are actually converting the int "321" to string. Slightly misleading, easy fix. Other than that, I like this solution.Trumpetweed
E
393

You can use sprintf to do it, or maybe snprintf if you have it:

char str[ENOUGH];
sprintf(str, "%d", 42);

Where the number of characters (plus terminating char) in the str can be calculated using:

(int)((ceil(log10(num))+1)*sizeof(char))
Ezzo answered 24/11, 2011 at 13:20 Comment(12)
To be sure tat ENOUGH is enough we can do it by malloc(sizeof(char)*(int)log10(num))Than
@Than Or even +2, considering that (int)log10(42) is 1.Lucindalucine
Or you can calculate it at compile-time: #define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)Spar
@Spar Note: ((CHAR_BIT * sizeof(int) - 1) / 3 + 2) fails for unusual, but possible, int widths such as 18. Just eliminate the -1.Lacey
@hauleth Still +2 instead of +1, even with ceil: ceil(log(100)) = 2.0, not 3. So +1 for the exact-powers-of-10, and another +1 for terminating null.Shuttle
You do not consider minus sign and locale: thousands separator and grouping. Please do it this way: use int length = snprintf(NULL, 0,"%d",42); to get length, and then alloc length+1 chars for the string.Atli
@Atli Calling snprintf with a NULL buffer to determine required buffer size is a great trick! Here's a comparison of the printf members for anyone who may be interested.Doud
Also, here's a concrete example of snprintf demonstrating how its reported buffer size may be used in other creative ways.Doud
How does your formula for the number of characters required work with negatives?Shing
As @Shuttle said, (int)((ceil(log10(num))+1)*sizeof(char)) is wrong. This should be correct for all possible int values (but I wouldn't use this abomination in real code): (int)((floor(log10(i==INT_MIN?INT_MAX:i<0?-i:i>0?i:1)+(i>=0?2:3)))). I dropped the sizeof(char) since it's always 1. Note: ISO C rules guarantee that INT_MIN and INT_MAX always have the same number of digits.Specific
If the number is zero, then this will fail, because in C arithmetic, log10(0) = -1...Santana
Another simple way to know exactly how many bytes you need: sizeof(EXPAND_AND_STRINGIFY(INT_MIN)) (given #define EXPAND_AND_STRINGIFY(macro) STRINGIFY(macro) and #define STRINGIFY(token) #token). This will take the - sign into account (and the maximum can never take more digits than the minimum in any integer representation that conforms to the standard, so this also takes an optional + into account), and the terminating null byte.Insolent
V
172

As pointed out in a comment, itoa() is not a standard, so better use the sprintf() approach suggested in the rival answer!


You can use the itoa() function to convert your integer value to a string.

Here is an example:

int num = 321;
char snum[5];

// Convert 123 to string [buf]
itoa(num, snum, 10);

// Print our string
printf("%s\n", snum);

If you want to output your structure into a file there isn't any need to convert any value beforehand. You can just use the printf format specification to indicate how to output your values and use any of the operators from printf family to output your data.

Vivle answered 24/11, 2011 at 13:22 Comment(7)
itoa is not standard - see e.g. #190729Circulate
@SeanRamey This itoa() suffers the same buffer overflow potential as gets().Lacey
itoa is not available in C (C99 at least). it is more available in C++Woodworm
How to get this without sprintf or itoa? Possibly while writing a custom standard library?Statampere
why did you pass argument as 10?Gheber
Add #include <stdlib.h>.Firecure
To be clear @AlexanderGalkin, the comment incorrectly says that you are converting "123 to string", whereas you are actually converting the int "321" to string. Slightly misleading, easy fix. Other than that, I like this solution.Trumpetweed
A
157

The short answer is:

snprintf( str, size, "%d", x );

The longer is: first you need to find out sufficient size. snprintf tells you length if you call it with NULL, 0 as first parameters:

snprintf( NULL, 0, "%d", x );

Allocate one character more for null-terminator.

#include <stdio.h> 
#include <stdlib.h>

int x = -42;
int length = snprintf( NULL, 0, "%d", x );
char* str = malloc( length + 1 );
snprintf( str, length + 1, "%d", x );
...
free(str);

If works for every format string, so you can convert float or double to string by using "%g", you can convert int to hex using "%x", and so on.

Atli answered 28/9, 2015 at 9:39 Comment(8)
#include <stdio.h> #include <stdlib.h>En
@En Thanks, it should really be mentioned that these header files need to be included.Pye
I love this one, being the most robust and "by the book" way.Woodworm
hey, I know this is super old answer, but why "+1" in malloc? is it for the '\0' ?Dede
Yes, +1 is for the '\0'. snprintf returns length not counting the terminating null character, but in second parameter it expects length with terminating null character, so length + 1.Atli
Is this a specified behavior?Spicy
@jinkwon Yes https://mcmap.net/q/56938/-is-snprintf-null-0-behavior-standardizedSpicy
I think there's a problem when you allocated memory to char* str. why didn't you check if there's a buffer overflow before malloc?Brom
A
45

After having looked at various versions of itoa for gcc, the most flexible version I have found that is capable of handling conversions to binary, decimal and hexadecimal, both positive and negative is the fourth version found at http://www.strudel.org.uk/itoa/. While sprintf/snprintf have advantages, they will not handle negative numbers for anything other than decimal conversion. Since the link above is either off-line or no longer active, I've included their 4th version below.

(Important Note: This code is GPLv3-licensed, so if you compile something with it, the result must be released under the same terms.)

/**
 * C++ version 0.4 char* style "itoa":
 * Written by Lukás Chmela
 * Released under GPLv3.
 */
char* itoa(int value, char* result, int base) {
    // check that the base if valid
    if (base < 2 || base > 36) { *result = '\0'; return result; }

    char* ptr = result, *ptr1 = result, tmp_char;
    int tmp_value;

    do {
        tmp_value = value;
        value /= base;
        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
    } while ( value );

    // Apply negative sign
    if (tmp_value < 0) *ptr++ = '-';
    *ptr-- = '\0';
  
    // Reverse the string
    while(ptr1 < ptr) {
        tmp_char = *ptr;
        *ptr--= *ptr1;
        *ptr1++ = tmp_char;
    }
    return result;
}
Antipater answered 24/5, 2014 at 2:16 Comment(14)
Also, this is considerably faster than sprintf. Could be important when dumping large files.Francium
@Eugene Ryabtsev C does not specify the performance rating of sprintf() and "this is considerably faster than sprintf" may be true on your compiler but not always hold. A compiler may look into sprintf(str, "%d", 42); and optimize it to an optimized itoa() like function - certainly faster than this user. code.Lacey
@chux Yes, a compiler could optimize sprintf(str, "%d", 42); as appending two const chars, but that is theory. In practice people don't sprintf const ints and the itoa above is nearly as optimized as it gets. At least you could be 100% sure you would not get orders of magnitude downgrade of a generic sprintf. It would be nice to see whatever counterexample you have in mind, with compiler version and settings.Francium
@Eugene Ryabtsev char str[3]; sprintf(str, "%d", 42); --> MOV #121A,W4, MOV W4,AF4, MOV #2A,W0 = 2A, MOV #0,W4, CALL 105E embedded compiler simple passes the buffer and 42 to a itoa()-like routine.Lacey
@chux If it ends in a call, it does not explain much unless we compare the called routine to the routine above (all the way down to no more calls; in assembly, if you like). If you do it as an answer with compiler version and settings, I will upvote it as useful.Francium
It would be good to provide a way to get the output length back. I've done that here: https://mcmap.net/q/56939/-print-int-from-signal-handler-using-write-or-async-safe-functions + unit tests.Mariellamarielle
what's result pointer here? since it returns char pointer also ?!Barram
@Barram result is a pointer that is a parameter passed to the function which was an array (or dynamically allocated block) in the calling function of sufficient size to hold the number converted to a string. Since the largest 64-bit number has 20 digits, the array must provide at least 21 bytes of storage (including the nul-terminating character for end-of-string). Generally char result[32]; in the calling function is fine.Antipater
Note that modern compilers (with optimizations turned on) will produce more efficient code on typical hardware if you just get the remainder with % instead of avoiding it by doing a separate multiplication. (And that such hand-optimizations are more likely to confuse and defeat optimization passes, making the hand-optimized code ultimately less efficient as optimization passes in compilers improve.) (I still +1'ed this answer though, because it's a good answer overall.)Insolent
@EugeneRyabtsev Of course, these debates depend upon rather we are concerned with speed or code compactness. When the later, our libraries are also a consideration. If we already need sprintf for something else in the program that lives in the "hot" code, then it's already sitting in the cache or mmapped and residing in RAM, so just use sprintf. Compiler optimizations are amazing these days. But for embedded programming, itoa can still be important. Remember the 80/20 rule!Bihari
@DavidC.Rankin From an optimization standpoint (and presuming it matters), this gets better with constants propagation. If allowed by your compiler (i.e, same translation unit or -flto enabled) the compiler will "clone" atoi, propagate the base as a constant, and you end up with a symbol called atoi.constprop.10 or such. If you only ever use atoi with the same base, the original atoi can be excluded from the final link.Bihari
@y.kaf. - result is an array of sufficient size passed in as a parameter which is filled by the function with a numerical representation of the value converted to a C-string. The address is returned as a convenience allowing immediate use, e..g printf ("%s\n", itoa(40, result, 10)); Where the results array could be declared as char result[64]; (or sized as desired)Antipater
@DavidC.Rankin what does zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz mean...Imide
@Imide the string literal zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz is simply the complete set of characters that allows for the representation of values in base2 to base36. (normally, you only deal with base2 (binary), base8 (octal), base10 (decimal) and base16 (hex), but there is no reason you can't convert to any base between 2 and 36.Antipater
C
13

Here's another way.

#include <stdio.h>

#define atoa(x) #x

int main(int argc, char *argv[])
{
    char *string = atoa(1234567890);
    printf("%s\n", string);
    return 0;
}
Consolatory answered 22/12, 2013 at 0:28 Comment(1)
Works only for constants, not for variables.Loreleilorelie
A
9

If you are using GCC, you can use the GNU extension asprintf function.

char* str;
asprintf(&str, "%i", 12313);
free(str);
Amateur answered 10/9, 2015 at 6:58 Comment(1)
A justification may be: "The sprintf function can be dangerous because it can potentially output more characters than can fit in the allocation size of the string s ... To avoid this problem, you can use snprintf or asprintf"Fabozzi
L
9

Converting anything to a string should either 1) allocate the resultant string or 2) pass in a char * destination and size. Sample code below:

Both work for all int including INT_MIN. They provide a consistent output unlike snprintf() which depends on the current locale.

Method 1: Returns NULL on out-of-memory.

#define INT_DECIMAL_STRING_SIZE(int_type) ((CHAR_BIT*sizeof(int_type)-1)*10/33+3)

char *int_to_string_alloc(int x) {
  int i = x;
  char buf[INT_DECIMAL_STRING_SIZE(int)];
  char *p = &buf[sizeof buf] - 1;
  *p = '\0';
  if (i >= 0) {
    i = -i;
  }
  do {
    p--;
    *p = (char) ('0' - i % 10);
    i /= 10;
  } while (i);
  if (x < 0) {
    p--;
    *p = '-';
  }
  size_t len = (size_t) (&buf[sizeof buf] - p);
  char *s = malloc(len);
  if (s) {
    memcpy(s, p, len);
  }
  return s;
}

Method 2: It returns NULL if the buffer was too small.

static char *int_to_string_helper(char *dest, size_t n, int x) {
  if (n == 0) {
    return NULL;
  }
  if (x <= -10) {
    dest = int_to_string_helper(dest, n - 1, x / 10);
    if (dest == NULL) return NULL;
  }
  *dest = (char) ('0' - x % 10);
  return dest + 1;
}

char *int_to_string(char *dest, size_t n, int x) {
  char *p = dest;
  if (n == 0) {
    return NULL;
  }
  n--;
  if (x < 0) {
    if (n == 0) return NULL;
    n--;
    *p++ = '-';
  } else {
    x = -x;
  }
  p = int_to_string_helper(p, n, x);
  if (p == NULL) return NULL;
  *p = 0;
  return dest;
}

[Edit] as request by @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3 is at least the maximum number of char needed to encode the some signed integer type as a string consisting of an optional negative sign, digits, and a null character..

The number of non-sign bits in a signed integer is no more than CHAR_BIT*sizeof(int_type)-1. A base-10 representation of a n-bit binary number takes up to n*log10(2) + 1 digits. 10/33 is slightly more than log10(2). +1 for the sign char and +1 for the null character. Other fractions could be used like 28/93.


Method 3: If one wants to live on the edge and buffer overflow is not a concern, a simple C99 or later solution follows which handles all int.

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

static char *itoa_simple_helper(char *dest, int i) {
  if (i <= -10) {
    dest = itoa_simple_helper(dest, i/10);
  }
  *dest++ = '0' - i%10;
  return dest;
}

char *itoa_simple(char *dest, int i) {
  char *s = dest;
  if (i < 0) {
    *s++ = '-';
  } else {
    i = -i;
  }
  *itoa_simple_helper(s, i) = '\0';
  return dest;
}

int main() {
  char s[100];
  puts(itoa_simple(s, 0));
  puts(itoa_simple(s, 1));
  puts(itoa_simple(s, -1));
  puts(itoa_simple(s, 12345));
  puts(itoa_simple(s, INT_MAX-1));
  puts(itoa_simple(s, INT_MAX));
  puts(itoa_simple(s, INT_MIN+1));
  puts(itoa_simple(s, INT_MIN));
}

Sample output

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648
Lacey answered 30/9, 2015 at 16:21 Comment(2)
Shouln't it be '0' + x % 10 instead of '0' - x % 10 (to map a binary integer between decimal 0 and decimal 9 to binary ascii encoding)?Thermopile
@étale-cohomology x%10 has the value of [-9 ... 0] as x <= 0, not 0 to 9. '0' - x % 10 is correct. Using the negative side of int avoids UB of i = -i; when i == INT_MIN, which this code never does.Lacey
D
6

sprintf is returning the bytes and adds a null byte as well:

# include <stdio.h>
# include <string.h>

int main() {
    char buf[1024];
    int n = sprintf( buf, "%d", 2415);
    printf("%s %d\n", buf, n);
}

Output:

2415 4
Delative answered 25/12, 2021 at 3:57 Comment(0)
F
3
/* Function return size of string and convert signed  *
 * integer to ascii value and store them in array of  *
 * character with NULL at the end of the array        */

int itoa(int value, char *ptr)
{
    int count = 0, temp;
    if(ptr == NULL)
        return 0;
    if(value == 0)
    {
        *ptr = '0';
        return 1;
    }

    if(value < 0)
    {
        value* = (-1);
        *ptr++ = '-';
        count++;
    }

    for(temp=value; temp>0; temp/=10, ptr++);
        *ptr = '\0';

    for(temp=value; temp>0; temp/=10)
    {
        *--ptr = temp%10 + '0';
        count++;
    }
    return count;
}
Faulkner answered 25/8, 2015 at 20:31 Comment(0)
T
0

Improved cnicutar answer.

Include:

#include <math.h> // log10, floor
#include <stdio.h> // sprintf
#include <stdlib.h> // abs

Create your number:

int num = 123;

Calculate length:

size_t len;
if (abs(num)) { // if not zero
    len = floor(log10(abs(num)) + 1); // taking 'round' numbers into account too
    if (num < 0) len++; // add minus sign
} else { // if zero
    len = 1;
}

Then you can store your string as a local variable:

char str[len];
sprintf(str, "%d", num);
// do stuff

or as a pointer:

char *str = malloc(len * sizeof(char));
sprintf(str, "%d", num);
// do stuff
free(str);

Hope that helps!

Tootle answered 21/3, 2023 at 7:50 Comment(0)
M
-4

Use function itoa() to convert an integer to a string

For example:

char msg[30];
int num = 10;
itoa(num,msg,10);
Morganne answered 6/10, 2018 at 8:5 Comment(1)
Already answered by @AlexanderGalkin : https://mcmap.net/q/56332/-how-can-i-convert-an-int-to-a-string-in-cBilliards

© 2022 - 2024 — McMap. All rights reserved.