Saltar al contenido

¿Cómo convertir un int a string en C?

septiembre 24, 2021
apple touch icon@2

Convertir cualquier cosa en una cadena debe 1) asignar la cadena resultante o 2) pasar en un char * Destino y tamaño. Código de muestra a continuación:

Ambos funcionan para todos int incluso INT_MIN. Proporcionan una salida constante a diferencia de snprintf() que depende de la localidad actual.

Método 1: devoluciones NULL en memoria insuficiente.

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

Método 2: vuelve NULL si el búfer era demasiado pequeño.

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] como solicitud de @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3 es al menos el número máximo de char necesario para codificar el tipo de entero con signo como una cadena que consta de un signo negativo opcional, dígitos y un carácter nulo.

El número de bits sin signo en un entero con signo no es más de CHAR_BIT*sizeof(int_type)-1. Una representación en base 10 de un n-bit número binario toma hasta n*log10(2) + 1 dígitos. 10/33 es un poco más que log10(2). +1 para el signo char y +1 para el carácter nulo. Se podrían usar otras fracciones como 28/93.


Método 3: si uno quiere vivir en el borde y el desbordamiento del búfer no es una preocupación, sigue una solución simple C99 o posterior que maneja todos 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) = ' ';
  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));
}

Salida de muestra

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648
close