Menu

String para int em C: atoi, strtol e converter números em texto

Convertendo entre texto e números em C: por que o atoi não consegue reportar erro, como usar strtol e strtod corretamente com endptr e errno, transformar números em strings com snprintf, e truques com um único dígito usando '0'.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Texto chega de usuários, arquivos e da linha de comando como caracteres. "42" são três bytes - '4', '2', '\0' - e nada nele é o número 42 até você converter. O C oferece duas gerações de funções de conversão: as curtas e antigas, que não conseguem reportar erros, e as mais longas, que conseguem. Esta página mostra as duas e explica por que programas reais usam o segundo conjunto.

A família antiga: atoi, atol, atof

Elas se leem como os seus nomes: ASCII para int, para long, para double. Um argumento, um resultado.

Espaços em branco iniciais são pulados, um sinal opcional é lido, os dígitos são consumidos e tudo depois é ignorado. Isso é conveniente até a entrada estar errada:

Os três imprimem 0. Não há código de retorno, nem sinalizador, nem forma de perguntar "isso funcionou?" - e um valor que estoura o int é comportamento indefinido em vez de um erro reportado. Para um literal fixo num programa de brinquedo isso é tolerável. Para qualquer coisa que uma pessoa ou um arquivo possa fornecer, é um gerador silencioso de bugs.

A ferramenta certa: strtol

O strtol (string to long) é a mesma conversão com dois canais para reportar o que aconteceu.

long strtol(const char *text, char **endptr, int base);

endptr recebe o primeiro caractere que a função não consumiu. base é a base numérica - use 10, ou 0 para deixar o prefixo do próprio literal decidir (0x para hexadecimal, 0 inicial para octal).

Ler o endptr responde às perguntas que o atoi não responde:

  • end == input significa que nada foi convertido - o texto não começava com um número.
  • *end != '\0' significa que havia conteúdo sobrando. Se isso é um erro, você decide: tudo bem ao interpretar "42 macas", e é um problema quando a linha inteira deveria ser um número.

O estouro é reportado à parte, pelo errno. Vale escrever o idioma completo e correto uma vez e reutilizá-lo:

Três detalhes tornam isso correto. O errno = 0 antes da chamada importa porque a biblioteca só atribui o errno; ela nunca o limpa, então um valor velho de uma chamada anterior seria lido como falha desta chamada. O strtol devolve long, que pode ser mais largo que int, então a verificação de intervalo contra INT_MIN/INT_MAX é separada do ERANGE. E devolver o sucesso como status enquanto entrega o valor por um ponteiro é como funções em C reportam "ou um valor, ou uma falha" - o valor de retorno não pode fazer os dois trabalhos.

strtoul é a contraparte sem sinal, e strtoll/strtoull tratam long long.

Outras bases

A base 16 lê hexadecimal; a base 0 inspeciona o prefixo e decide sozinha.

A base 0 é uma armadilha num caso específico: um decimal com zero à esquerda como "012" é lido como octal e sai como 10. Se sua entrada é decimal, diga 10 explicitamente.

Ponto flutuante: strtod

O strtod tem a mesma forma para double, e o atof tem o mesmo defeito do atoi.

O strtod também aceita notação científica ("1.5e3"), floats hexadecimais e as palavras "inf" e "nan". O locale afeta o separador decimal, o que surpreende quem lê arquivos escritos em outro lugar - no locale padrão "C" o separador é sempre um ponto.

Números para texto: snprintf

No caminho inverso, o snprintf é a resposta padrão. Ele escreve no máximo o tamanho que você indicar, sempre termina a string, e devolve o comprimento de que o resultado completo precisaria.

O valor de retorno é a verificação de truncamento. Se ele for maior ou igual ao tamanho do buffer, o texto não coube:

Duas coisas às quais não recorrer: itoa não faz parte do C padrão, então código que o usa não compila em todo lugar; e sprintf é o snprintf sem o limite de tamanho, o que significa que ele vai escrever além do fim do seu buffer sem reclamar.

Caracteres isolados e o '0'

Os caracteres de dígito de '0' a '9' têm garantia de serem consecutivos, então uma simples subtração converte entre um caractere de dígito e o seu valor.

Só os dígitos se comportam assim - letras não precisam ser consecutivas, então c - 'a' não é portável para aritmética no alfabeto. Proteja a subtração com isdigit antes de confiar nela:

A conversão para unsigned char é obrigatória pela mesma razão vista em strings: as funções de <ctype.h> são indefinidas para argumentos negativos, e um char puro pode ter sinal.

Qual função usar

  • Texto de um usuário, de um arquivo ou do argvstrtol / strtod com a verificação completa.
  • Um literal que você mesmo escreveu e controla → atoi é aceitável, ainda que sem graça.
  • Número para dentro de um buffer → snprintf, e confira o valor de retorno.
  • Um único caractere de dígito → subtraia '0', depois do isdigit.
  • Nunca → gets, sprintf, itoa.

Perguntas frequentes

Como converter uma string em int em C?

strtol(texto, &end, 10) é a resposta correta: ela devolve o valor, aponta end para o primeiro caractere que não consumiu e reporta estouro através do errno. atoi(texto) é mais curto, mas devolve 0 tanto para "0" quanto para "ola", sem como distinguir os dois.

O que há de errado com o atoi em C?

Ele não consegue reportar falha. atoi("abc") devolve 0, indistinguível de um zero de verdade, e o estouro é comportamento indefinido em vez de um erro reportado. Use strtol sempre que o texto vier de um usuário, de um arquivo ou de um argumento de linha de comando.

Como converter um int em string em C?

snprintf(buf, sizeof buf, "%d", n). É padrão, limitado pelo tamanho do buffer, e devolve o número de caracteres de que o resultado completo precisaria - então um valor de retorno igual ou maior que sizeof buf avisa que o texto foi truncado. itoa não é C padrão.

Como transformar o caractere '7' no número 7 em C?

Subtraia '0': int digito = c - '0';. Os caracteres de dígito são consecutivos em todo conjunto de caracteres do C, então a subtração dá de 0 a 9. Proteja isso com isdigit((unsigned char)c) antes, já que a aritmética não faz sentido para qualquer outra coisa.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR