如何在C中将int转换为字符串?


225

如何将int(整数)转换为字符串?我正在尝试制作一个将a的数据struct转换为字符串以将其保存在文件中的函数。


3
printf或它的一个堂兄应该做到这一点
pmg


1
您可能还希望看到有关序列化的FAQ,以及可能与C中的序列化有关的以下问题:(a)(b)(c)以实现您的实际意图。
moooeeeep 2011年

2
我在这里惯常的宠物语气。您不想转换任何东西;您想要获取一个字符串,其中包含(的基数为10?)表示的值int。是的,我知道。这是一个非常常见的捷径,但仍然困扰着我。
dmckee ---前主持人小猫,2014年

Answers:


92

编辑: 正如评论中指出的那样,这itoa()不是一个标准,因此最好使用竞争性答案中建议的sprintf()方法!


您可以使用itoa()函数整数值转换为字符串。

这是一个例子:

int num = 321;
char snum[5];

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

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

如果要将结构输出到文件中,则无需事先转换任何值。您可以仅使用printf格式规范来指示如何输出值,以及使用printf系列中的任何运算符来输出数据。


28
itoa是不是标准-例如参见stackoverflow.com/questions/190229/...
保罗- [R

1
@PaulR现在我不知道!感谢您的澄清。
Christian Rau

1
@PaulR谢谢,我不知道!
亚历山大·加尔金

@SeanRamey itoa()遭受与相同的缓冲区溢出可能性gets()
chux-恢复莫妮卡

itoa在C语言中不可用(至少C99)。它在C ++中更有效
Motti Shneor

210

您可以使用sprintf它来做,或者snprintf如果有的话:

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

其中的字符数(加上终止字符)str可以使用以下公式计算:

(int)((ceil(log10(num))+1)*sizeof(char))

9
可以肯定的达ENOUGH足够我们可以做到这一点malloc(sizeof(char)*(int)log10(num))
Hauleth

2
@Hauleth甚至+2,考虑到(int)log10(42)1
Christian Rau

23
或者,您可以在编译时进行计算:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth即使使用ceil,也仍然是+2而不是+1:ceil(log(100))= 2.0,而不是3。所以+1表示10的次幂,另外+1表示终止null。
不只是yeti

24
您不考虑减号和区域设置:千位分隔符和分组。请按以下方式进行操作:用于int length = snprintf(NULL, 0,"%d",42);获取长度,然后length+1为字符串分配字符。
user2622016 2015-09-28

69

简短的答案是:

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

较长的是:首先,您需要找到足够的大小。snprintf告诉您使用NULL, 0第一个参数调用时的长度:

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

为空终止符再分配一个字符。

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

如果适用于所有格式字符串,则可以使用来将float或double转换为字符串"%g",可以使用来将int转换为十六进制"%x",依此类推。


3
#include <stdio.h> #include <stdlib.h>
1821961年

@ user1821961谢谢,应该真正提到需要包含这些头文件。
byxor

我喜欢这种方式,它是最可靠且“按书”的方式。
Motti Shneor

30

看完gcc的itoa的各种版本后,我发现最灵活的版本能够处理到二进制,十进制和十六进制的转换,正负都是第四个版本,可从http://www.strudel.org找到。 .uk / itoa /。尽管sprintf/ snprintf具有优势,但除了十进制转换外,它们不会处理负数。由于上面的链接已离线或不再有效,因此我在下面包括了它们的第4版:

/**
 * 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';
    while(ptr1 < ptr) {
        tmp_char = *ptr;
        *ptr--= *ptr1;
        *ptr1++ = tmp_char;
    }
    return result;
}

4
而且,这比sprintf快得多。转储大文件时可能很重要。
Eugene Ryabtsev 2014年

@Eugene Ryabtsev C没有指定的性能等级,sprintf()并且“这比sprintf快得多”在您的编译器上可能是正确的,但并不总是如此。编译器可能会调查sprintf(str, "%d", 42);并将其优化为优化的itoa()类似函数-当然比该用户快。码。
chux-恢复莫妮卡2015年

3
@chux是的,编译器可以优化sprintf(str, "%d", 42);为附加两个const char,但这是理论上的。在实践中,人们不会使用sprintf const ints,并且上面的itoa几乎是尽可能优化的。至少您可以100%确定不会将通用sprintf降级几个数量级。很高兴看到您想到的任何反例,以及编译器的版本和设置。
Eugene Ryabtsev

1
@chux如果它以调用结尾,那么除非我们将被调用的例程与上面的例程进行比较(直到您不再喜欢,否则不再进行更多调用;如果愿意,可以在汇编中),否则它不会解释太多。如果您将其作为对编译器版本和设置的解答,我将其视作有用。
Eugene Ryabtsev

2
最好提供一种方法来恢复输出长度。我在这里做到了:stackoverflow.com/a/52111436/895245 +单元测试。
Ciro Santilli郝海东冠状病六四事件法轮功

9

这是旧的,但这是另一种方式。

#include <stdio.h>

#define atoa(x) #x

int main(int argc, char *argv[])
{
    char *string = atoa(1234567890);
    printf("%s\n", string);
    return 0;
}

32
仅适用于常量,不适用于变量。
赤裸裸的


7

将任何内容转换为字符串都应1)分配结果字符串或2)传递char *目的地和大小。下面的示例代码:

所有这两种工作int包括INT_MIN。它们提供一致的输出snprintf(),这取决于当前的语言环境。

方法1:NULL内存不足时返回。

#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;
}

方法2:NULL如果缓冲区太小,则返回。

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

[编辑]应@Alter Mann的要求

(CHAR_BIT*sizeof(int_type)-1)*10/33+3至少是char将某种带符号整数类型编码为由可选的负号,数字和空字符组成的字符串所需的最大数量。

有符号整数中的非符号位数不超过CHAR_BIT*sizeof(int_type)-1n-bit二进制数的以10为基数的表示形式最多包含n*log10(2) + 1数字。 10/33比略多log10(2)。+1表示符号char,+ 1表示空字符。可以使用其他分数,例如28/93。


方法3:如果您希望生活在边缘并且缓冲区溢出不是问题,那么可以采用一种简单的C99或更高版本的解决方案来处理所有问题 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));
}

样品输出

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

嗨,chux,您知道是否有任何方法可以公开glibc内部实现?sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/...
西罗桑蒂利郝海东冠状病六四事件法轮功

1
@CiroSantilli新疆改造中心六四事件法轮功我不熟悉glibc内部实现。
chux-恢复莫妮卡

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

2

如果要将结构输出到文件中,则无需事先转换任何值。您可以仅使用printf格式规范来指示如何输出值,以及使用printf系列中的任何运算符来输出数据。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.