Преобразование чего-либо в строку должно либо 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)-1
.Базовое-10 представление n
-битного двоичного числа занимает до 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