ChatGPT解决这个技术问题 Extra ChatGPT

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

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

printf 或其表亲之一应该可以解决问题
您可能还希望查看有关序列化的 this FAQ,以及与 C 中的序列化相关的以下问题:(a)(b)(c) 以实现您的实际意图。
我通常在这里的宠物语义上的烦恼。你不想转换任何东西;您想获得一个包含 int 值的(以 10 为基数?)表示形式的字符串。是的,我知道。这是一个非常常见的捷径,但它仍然困扰着我。
Converting int to string in c 的可能重复项

D
Dave Jarvis

您可以使用 sprintf 来执行此操作,或者如果您有它,也可以使用 snprintf

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

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

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

为了确保 tat ENOUGH 就足够了,我们可以通过 malloc(sizeof(char)*(int)log10(num))
@Hauleth 甚至 +2,考虑到 (int)log10(42)1
或者您可以在编译时计算它:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
@hauleth 仍然 +2 而不是 +1,即使使用 ceil:ceil(log(100)) = 2.0,而不是 3。所以 +1 表示 10 的精确幂,另一个 +1 表示终止 null。
您不考虑减号和语言环境:千位分隔符和分组。请这样做:使用 int length = snprintf(NULL, 0,"%d",42); 获取长度,然后为字符串分配 length+1 个字符。
A
Alexander Galkin

编辑: 正如评论中所指出的,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 format specification 来指示如何输出您的值,并使用 printf family 中的任何运算符来输出您的数据。


itoa 不是标准的 - 参见例如 stackoverflow.com/questions/190229/…
@PaulR现在我不知道!感谢您的澄清。
@PaulR 谢谢,我不知道!
@SeanRamey 此 itoa() 遭受与 gets() 相同的缓冲区溢出可能性。
itoa 在 C 中不可用(至少 C99)。它在 C++ 中更可用
A
APhillips

简短的回答是:

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

更长的是:首先你需要找出足够的大小。如果您使用 NULL, 0 作为第一个参数调用它,snprintf 会告诉您长度:

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

如果适用于所有格式字符串,那么您可以使用 "%g" 将 float 或 double 转换为字符串,您可以使用 "%x" 将 int 转换为 hex,依此类推。


#include #include
@user1821961 谢谢,确实应该提到这些头文件需要包含在内。
嘿,我知道这是超级旧的答案,但为什么在 malloc 中使用“+1”?是为了 '\0' 吗?
是的,+1 用于“\0”。 snprintf 返回长度不计算终止空字符,但在第二个参数中,它期望长度与终止空字符,因此长度 + 1。
a
ahogen

在查看了用于 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;
}

此外,这比 sprintf 快得多。转储大文件时可能很重要。
@chux 是的,编译器可以将 sprintf(str, "%d", 42); 优化为附加两个 const 字符,但这是理论上的。在实践中,人们不会 sprintf const ints 并且上面的 itoa 几乎与它得到的优化一样。至少您可以 100% 确定您不会将通用 sprintf 降级几个数量级。很高兴看到您想到的任何反例,以及编译器版本和设置。
@Eugene Ryabtsev char str[3]; sprintf(str, "%d", 42); --> MOV #121A,W4, MOV W4,AF4, MOV #2A,W0 = 2A, MOV #0,W4, CALL 105E 嵌入式编译器简单地将缓冲区和 42 传递给类似 itoa() 的例程。
@chux如果它以调用结束,除非我们将被调用的例程与上面的例程进行比较,否则它不会解释太多(一直到不再调用;如果您愿意,可以在汇编中)。如果您将其作为编译器版本和设置的答案,我会认为它很有用。
最好提供一种方法来恢复输出长度。我在这里做了:stackoverflow.com/a/52111436/895245 + 单元测试。
M
Mahonri Moriancumer

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

#include <stdio.h>

#define atoa(x) #x

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

仅适用于常量,不适用于变量。
如果我在其中放一个宏,为什么它不起作用......?它不是一个常数吗?
c
chux - Reinstate Monica

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

两者都适用于所有 int,包括 INT_MIN。与 snprintf() 不同,它们提供一致的输出,而 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 位二进制数的 base-10 表示最多占用 n*log10(2) + 1 位。 10/33 略大于 log10(2)。 +1 符号 char 和 +1 空字符。可以使用其他分数,例如 28/93。

方法 3:如果想要生活在边缘并且不担心缓冲区溢出,则可以使用简单的 C99 或更高版本的解决方案来处理 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));
}

样本输出

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

嘿 chux,你知道有没有办法暴露 glibc 内部实现? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
@CiroSantilli新疆改造中心六四事件轮法功我不熟悉glibc内部实现。
不应该是 '0' + x % 10 而不是 '0' - x % 10 (将十进制 0 和十进制 9 之间的二进制整数映射到二进制 ascii 编码)?
@étale-cohomology x%10 的值为 [-9 ... 0] 作为 x <= 0,而不是 0 到 9。'0' - x % 10 是正确的。在 i == INT_MIN 时使用 int 的负数可以避免 i = -i; 的 UB,而这段代码从来没有这样做过。
@étale-cohomology UB --> Undefined behavior。否定 INT_MIN 是 UB。
s
sth

如果你使用 GCC,你可以使用 GNU 扩展 asprintf 函数。

char* str;
asprintf (&str, "%i", 12313);
free(str);

u
user2374601

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


D
Dummy00001
/*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;
     }

b
baz

sprintf 正在返回字节并添加空字节:

# include <stdio.h>
# include <string.h>
int main() {
    char buf[ 1024];
    int n = sprintf( buf, "%d", 2415);
    printf( "%s %d\n", buf, n);
}

输出:

2415 4

M
Morteza Jalambadani

使用函数 itoa()integer 转换为 string

例如:

char msg[30];
int num = 10;
itoa(num,msg,10);

@AlexanderGalkin 已经回答:stackoverflow.com/a/8257754/6872717