¿Cómo convertir un int a una cadena en C?


225

¿Cómo se convierte un int(entero) en una cadena? Estoy tratando de hacer una función que convierta los datos de a structen una cadena para guardarlos en un archivo.


3
printfo uno de sus primos debería hacer el truco
pmg


1
También es posible que desee ver estas Preguntas frecuentes sobre la serialización, y tal vez las siguientes preguntas relacionadas con la serialización en C: (a) , (b) , (c) para lograr su intención real.
moooeeeep

2
Mi habitual mascota semántica molesta aquí. No quieres convertir nada; desea obtener una cadena que contenga una representación (¿base 10?) del valor de int. Si lo se. Es un atajo muy común, pero todavía me molesta.
dmckee --- ex gatito moderador

posible duplicado de Convertir int a string en c
nawfal

Respuestas:


92

EDITAR: Como se señaló en el comentario, itoa()no es un estándar, ¡así que mejor use el enfoque sprintf () sugerido en la respuesta rival!


Puede usar la itoa()función para convertir su valor entero en una cadena.

Aquí hay un ejemplo:

int num = 321;
char snum[5];

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

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

Si desea generar su estructura en un archivo, no es necesario convertir ningún valor de antemano. Puede usar la especificación del formato printf para indicar cómo generar sus valores y utilizar cualquiera de los operadores de la familia printf para generar sus datos.


30
itoano es estándar; consulte, por ejemplo, stackoverflow.com/questions/190229/…
Paul R

1
@PaulR ¡Ahora no lo sabía! Gracias por la aclaración.
Christian Rau

1
@PaulR ¡Gracias, no lo sabía!
Alexander Galkin

@SeanRamey Esto itoa()sufre el mismo potencial de desbordamiento de búfer que gets().
chux - Restablecer Monica

itoa no está disponible en C (C99 al menos). está más disponible en C ++
Motti Shneor

211

Puedes usarlo sprintfpara hacerlo, o tal vez snprintfsi lo tienes:

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

Donde strse puede calcular el número de caracteres (más el carácter final) en :

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

99
Para estar seguros de que tat ENOUGHes suficiente, podemos hacerlomalloc(sizeof(char)*(int)log10(num))
Hauleth

2
@Hauleth O incluso +2, considerando que (int)log10(42)es así 1.
Christian Rau

23
O se puede calcular en tiempo de compilación:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
CAF

44
@hauleth Todavía +2 en lugar de +1, incluso con ceil: ceil (log (100)) = 2.0, no 3. Entonces +1 para las potencias exactas de 10, y otro +1 para terminar nulo.
not-just-yeti

24
No tiene en cuenta el signo menos y la configuración regional: separador de miles y agrupación. int length = snprintf(NULL, 0,"%d",42);Hágalo de esta manera: use para obtener longitud y luego asigne length+1caracteres para la cadena.
user2622016

70

La respuesta corta es:

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

Cuanto más largo sea: primero debe averiguar el tamaño suficiente. snprintfle dice longitud si lo llama con los NULL, 0primeros parámetros:

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

Asigne un carácter más para nulo-terminador.

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

Si funciona para cada cadena de formato, por lo que puede convertir flotante o doble a cadena usando "%g", puede convertir int a hexadecimal usando "%x", y así sucesivamente.


3
#include <stdio.h> #include <stdlib.h>
user1821961

@ user1821961 Gracias, realmente debería mencionarse que estos archivos de encabezado deben incluirse.
byxor

Me encanta este, siendo el más robusto y "por el libro".
Motti Shneor

30

Después de haber examinado varias versiones de itoa para gcc, la versión más flexible que he encontrado que es capaz de manejar conversiones a binario, decimal y hexadecimal, tanto positiva como negativa, es la cuarta versión encontrada en http://www.strudel.org .uk / itoa / . Si bien sprintf/ snprintftienen ventajas, no manejarán números negativos para otra cosa que no sea la conversión decimal. Dado que el enlace anterior está fuera de línea o ya no está activo, he incluido su cuarta versión a continuación:

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

44
Además, esto es considerablemente más rápido que sprintf. Podría ser importante al volcar archivos grandes.
Eugene Ryabtsev

@Eugene Ryabtsev C no especifica la calificación de rendimiento de sprintf()y "esto es considerablemente más rápido que sprintf" puede ser cierto en su compilador pero no siempre se cumple. Un compilador puede analizarlo sprintf(str, "%d", 42);y optimizarlo para una itoa()función similar optimizada , ciertamente más rápido que este usuario. código.
chux

3
@chux Sí, un compilador podría optimizar sprintf(str, "%d", 42);como anexar dos caracteres constantes, pero eso es teoría. En la práctica, las personas no realizan constantes de sprint y el itoa anterior está casi tan optimizado como parece. Al menos, podría estar 100% seguro de que no obtendría órdenes de magnitud de degradación de un sprintf genérico. Sería bueno ver cualquier contraejemplo que tenga en mente, con la versión y la configuración del compilador.
Eugene Ryabtsev

1
@chux Si termina en una llamada, no explica mucho a menos que comparemos la rutina llamada con la rutina anterior (hasta llegar a no más llamadas; en conjunto, si lo desea). Si lo hace como respuesta con la versión y la configuración del compilador, lo votaré como útil.
Eugene Ryabtsev

2
Sería bueno proporcionar una forma de recuperar la longitud de salida. Lo he hecho aquí: stackoverflow.com/a/52111436/895245 + pruebas unitarias.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9

Esto es viejo pero aquí hay otra forma.

#include <stdio.h>

#define atoa(x) #x

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

32
Funciona solo para constantes, no para variables.
Nakedible

7

Si está usando GCC, puede usar la extensión GNU asprintf function.

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

7

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

Ambos funcionan para todos, intincluidos INT_MIN. Proporcionan una salida consistente a diferencia de lo snprintf()que depende de la configuración regional actual.

Método 1: Devoluciones NULLen 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 = '\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;
}

Método 2: vuelve NULLsi 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;
}

[Editar] como solicitud de @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3es al menos el número máximo charnecesario para codificar algún 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 que CHAR_BIT*sizeof(int_type)-1. Una representación en base 10 de un nnúmero binario de un bit ocupa hasta n*log10(2) + 1dígitos. 10/33es un poco más que log10(2). +1 para el signo chary +1 para el carácter nulo. Otras fracciones podrían usarse como 28/93.


Método 3: Si uno quiere vivir al límite y el desbordamiento del búfer no es una preocupación, sigue una solución simple C99 o posterior que maneja todo 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));
}

Salida de muestra

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Hola chux, ¿sabes si hay alguna forma de exponer la implementación interna de glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 No estoy familiarizado con la implementación interna de glibc.
chux - Restablecer Monica

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

Si desea generar su estructura en un archivo, no es necesario convertir ningún valor de antemano. Puede usar la especificación del formato printf para indicar cómo generar sus valores y utilizar cualquiera de los operadores de la familia printf para generar sus datos.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.