如何将 int
(整数)转换为字符串?我正在尝试制作一个将 struct
的数据转换为字符串以将其保存在文件中的函数。
printf
或其表亲之一应该可以解决问题
int
值的(以 10 为基数?)表示形式的字符串。是的,我知道。这是一个非常常见的捷径,但它仍然困扰着我。
您可以使用 sprintf
来执行此操作,或者如果您有它,也可以使用 snprintf
:
char str[ENOUGH];
sprintf(str, "%d", 42);
其中 str
中的字符数(加上终止字符)可以使用以下方法计算:
(int)((ceil(log10(num))+1)*sizeof(char))
编辑: 正如评论中所指出的,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/…
itoa()
遭受与 gets()
相同的缓冲区溢出可能性。
简短的回答是:
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,依此类推。
在查看了用于 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(str, "%d", 42);
优化为附加两个 const 字符,但这是理论上的。在实践中,人们不会 sprintf const ints 并且上面的 itoa 几乎与它得到的优化一样。至少您可以 100% 确定您不会将通用 sprintf 降级几个数量级。很高兴看到您想到的任何反例,以及编译器版本和设置。
char str[3]; sprintf(str, "%d", 42);
--> MOV #121A,W4, MOV W4,AF4, MOV #2A,W0 = 2A, MOV #0,W4, CALL 105E
嵌入式编译器简单地将缓冲区和 42 传递给类似 itoa()
的例程。
这是旧的,但这是另一种方式。
#include <stdio.h>
#define atoa(x) #x
int main(int argc, char *argv[])
{
char *string = atoa(1234567890);
printf("%s\n", string);
return 0;
}
将任何内容转换为字符串应该 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)-1
。 n
位二进制数的 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
'0' + x % 10
而不是 '0' - x % 10
(将十进制 0 和十进制 9 之间的二进制整数映射到二进制 ascii 编码)?
x%10
的值为 [-9 ... 0] 作为 x <= 0
,而不是 0 到 9。'0' - x % 10
是正确的。在 i == INT_MIN
时使用 int
的负数可以避免 i = -i;
的 UB,而这段代码从来没有这样做过。
INT_MIN
是 UB。
如果你使用 GCC,你可以使用 GNU 扩展 asprintf 函数。
char* str;
asprintf (&str, "%i", 12313);
free(str);
如果要将结构输出到文件中,则无需事先转换任何值。您可以只使用 printf 格式规范来指示如何输出您的值并使用 printf 系列中的任何运算符来输出您的数据。
/*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;
}
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
使用函数 itoa()
将 integer 转换为 string
例如:
char msg[30];
int num = 10;
itoa(num,msg,10);
不定期副业成功案例分享
ENOUGH
就足够了,我们可以通过malloc(sizeof(char)*(int)log10(num))
(int)log10(42)
是1
。#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
int length = snprintf(NULL, 0,"%d",42);
获取长度,然后为字符串分配length+1
个字符。