Como converter um int para string em C?


225

Como você converte um int(inteiro) em uma string? Eu estou tentando fazer uma função que converte os dados de um structem uma seqüência de caracteres para salvá-lo em um arquivo.


3
printfou um de seus primos deve fazer o truque
PMG


1
você também pode querer consultar estas perguntas frequentes sobre serialização e talvez as seguintes perguntas relacionadas à serialização em C: (a) , (b) , (c) para atingir sua intenção real.
moooeeeep

2
Minha irritação semântica habitual aqui. Você não quer converter nada; você deseja obter uma string contendo uma representação (base 10?) do valor de int. Sim, eu sei. É um atalho muito comum, mas ainda me incomoda.
dmckee --- ex-moderador gatinho

possível duplicata de conversão int para string em c
Nawfal

Respostas:


92

EDIT: Como apontado no comentário, itoa()não é um padrão, portanto, use melhor a abordagem sprintf () sugerida na resposta rival!


Você pode usar a itoa()função para converter seu valor inteiro em uma sequência.

Aqui está um exemplo:

int num = 321;
char snum[5];

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

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

Se você deseja exibir sua estrutura em um arquivo, não há necessidade de converter nenhum valor antecipadamente. Você pode apenas usar a especificação de formato printf para indicar como imprimir seus valores e usar qualquer um dos operadores da família printf para imprimir seus dados.


30
itoanão é padrão - veja, por exemplo, stackoverflow.com/questions/190229/…
Paul R

1
@PaulR Agora eu não sabia disso! Obrigado pelo esclarecimento.
Christian Rau

1
@PaulR Obrigado, eu não sabia disso!
precisa

@SeanRamey Isso itoa()sofre o mesmo potencial de estouro de buffer que gets().
chux - Restabelece Monica

itoa não está disponível em C (pelo menos C99). está mais disponível em C ++
Motti Shneor 27/03/19

211

Você pode usar sprintfpara fazer isso, ou talvez snprintfse tiver:

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

Onde o número de caracteres (mais o caractere final) no strpode ser calculado usando:

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

9
Para ter certeza tat ENOUGHé suficiente, podemos fazê-lomalloc(sizeof(char)*(int)log10(num))
Hauleth

2
@ Hauleth Ou mesmo +2, considerando que (int)log10(42)é 1.
Christian Rau

23
Ou você pode calculá-lo em tempo de compilação:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth Ainda +2 em vez de +1, mesmo com ceil: ceil (log (100)) = 2.0, não 3. Portanto, +1 para a potência exata de 10 e outra +1 para terminar nulo.
não-apenas-yeti

24
Você não considera sinal de menos e localidade: separador e agrupamento de milhares. Por favor, faça desta maneira: use int length = snprintf(NULL, 0,"%d",42);para obter comprimento e, em seguida, aloque length+1chars para a string.
user2622016

70

A resposta curta é:

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

Quanto mais tempo: primeiro você precisa descobrir o tamanho suficiente. snprintfinforma o comprimento se você o chamar com os NULL, 0primeiros parâmetros:

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

Aloque mais um caractere para terminador nulo.

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

Se funcionar para todas as strings de formato, você poderá converter float ou double em string usando "%g", você pode converter int em hexadecimal usando "%x"e assim por diante.


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

@ user1821961 Obrigado, deve realmente ser mencionado que esses arquivos de cabeçalho precisam ser incluídos.
Bydor

Eu amo esse, por ser o mais robusto e "pelo jeito".
Motti Shneor 27/03/19

30

Depois de analisar várias versões do itoa para o gcc, a versão mais flexível que achei capaz de lidar com conversões em binárias, decimais e hexadecimais, positivas e negativas, é a quarta versão encontrada em http://www.strudel.org .uk / itoa / . Enquanto sprintf/ snprintftêm vantagens, eles não vão lidar com números negativos para outra coisa senão a conversão decimal. Como o link acima está off-line ou não está mais ativo, incluímos a quarta versão abaixo:

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

4
Além disso, isso é consideravelmente mais rápido que o sprintf. Pode ser importante ao descarregar arquivos grandes.
Eugene Ryabtsev

@Eugene Ryabtsev C não especifica a classificação de desempenho sprintf()e "isso é consideravelmente mais rápido que o sprintf" pode ser verdade no seu compilador, mas nem sempre é válido. Um compilador pode procurar sprintf(str, "%d", 42);e otimizar para uma itoa()função semelhante otimizada - certamente mais rápido que esse usuário. código.
chux - Restabelece Monica

3
@chux Sim, um compilador pode otimizar sprintf(str, "%d", 42);como anexar dois caracteres const, mas isso é teoria. Na prática, as pessoas não correm constantemente e a itoa acima é quase tão otimizada quanto possível. Pelo menos você pode ter 100% de certeza de que não obteria ordens de magnitude inferior a um sprintf genérico. Seria bom ver qualquer contra-exemplo que você tenha em mente, com a versão e as configurações do compilador.
Eugene Ryabtsev

1
@chux Se termina em uma chamada, não explica muito, a menos que comparemos a rotina chamada com a rotina acima (até não mais chamadas; em montagem, se você preferir). Se você fizer isso como uma resposta com a versão e as configurações do compilador, votarei como útil.
Eugene Ryabtsev

2
Seria bom fornecer uma maneira de recuperar o comprimento da saída. Eu fiz isso aqui: stackoverflow.com/a/52111436/895245 + testes de unidade.
Ciro Santilli escreveu

9

Isso é antigo, mas aqui está outra maneira.

#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 apenas para constantes, não para variáveis.
Nakedible 03/03

7

Se você estiver usando o GCC, poderá usar a função de extensão GNU asprintf.

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

7

A conversão de qualquer coisa em uma sequência de caracteres deve 1) alocar a sequência resultante ou 2) passar em um char *destino e tamanho. Código de exemplo abaixo:

Ambos funcionam para todos, intinclusive INT_MIN. Eles fornecem uma saída consistente, diferente da snprintf()que depende do código do idioma atual.

Método 1: Retorna NULLem falta de memória.

#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: Retorna NULLse o buffer era muito pequeno.

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] a pedido de @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3é pelo menos o número máximo charnecessário para codificar algum tipo de número inteiro assinado como uma sequência que consiste em um sinal negativo opcional, dígitos e um caractere nulo.

O número de bits não assinados em um número inteiro assinado não passa de CHAR_BIT*sizeof(int_type)-1 . Uma representação de base 10 de um nnúmero binário de bits depende de n*log10(2) + 1dígitos. 10/33é um pouco mais que log10(2). +1 para o sinal chare +1 para o caractere nulo. Outras frações podem ser usadas como 28/93.


Método 3: Se alguém deseja viver no limite e o estouro de buffer não é uma preocupação, segue uma solução C99 simples ou posterior que lida com 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) = '\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));
}

Saída de amostra

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Ei chux, você sabe se existe alguma maneira de expor a implementação interna da glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli publicou

1
@CiroSantilli 法轮功 改造 中心 六四 事件 法轮功 Não estou familiarizado com a implementação interna da glibc.
chux - Restabelece 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

Se você deseja exibir sua estrutura em um arquivo, não há necessidade de converter nenhum valor antecipadamente. Você pode apenas usar a especificação de formato printf para indicar como imprimir seus valores e usar qualquer um dos operadores da família printf para imprimir seus dados.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.