Converta um dígito de caractere para o número inteiro correspondente em C


103

Existe uma maneira de converter um caractere em um inteiro em C?

Por exemplo, de '5'a 5?

Respostas:


149

De acordo com outras respostas, está bom:

char c = '5';
int x = c - '0';

Além disso, para verificação de erros, você pode desejar verificar se isdigit (c) é verdadeiro primeiro. Observe que você não pode fazer o mesmo de forma totalmente portátil para letras, por exemplo:

char c = 'b';
int x = c - 'a'; // x is now not necessarily 1

O padrão garante que os valores de char para os dígitos de '0' a '9' sejam contíguos, mas não oferece garantia para outros caracteres, como letras do alfabeto.


3
@Paul Tomblin: Sim para dígitos e não letras, porque, como eu disse na resposta, o padrão garante '0' a '9' são contíguos, mas não oferece tais garantias para outros caracteres como 'a' a 'z'.
Chris Young

char c = 'b'; int x = c - 'a'; então x será 1 apenas em ASCII?
Pan de

@Pan Em qualquer codificação, incluindo ASCII, que tenha 'b' 1 a mais do que 'a'. Isso ainda é verdadeiro em EBCDIC, no entanto, torna ('j' - 'i') == 8.
Chris Young

@ChrisYoung Por quê? Porque em EBCDIC, 'j' não é 1 mais do que 'i'?
Pan

2
O que estou perdendo aqui onde o atoi não é usado?
Daniel

41

Subtraia '0' assim:

int i = c - '0';

O padrão C garante que cada dígito no intervalo '0'..'9'seja um maior que o dígito anterior (na seção 5.2.1/3do rascunho C99 ). O mesmo vale para C ++.


1
Esta resposta seria melhor se você mencionasse que um char é / já / efetivamente um inteiro, um sinal definido de implementação (ou seja, pode ser assinado ou não assinado) e é CHAR_BITS longo.
Arafangion

Eu não tinha certeza de saber que isso realmente o ajuda. mas Chris fez uma boa observação com a..z sendo não necessariamente contíguo. eu deveria ter mencionado isso em vez disso. agora ele ganhou a corrida :)
Johannes Schaub - litb

1
A sua é melhor porque você qualificou sua resposta, porém - Chris poderia muito bem ter inventado suas coisas. :)
Arafangion

obrigado pela apreciação. Admito que não tinha certeza sobre o estado de C. então olhei para cima e, como já estava lá, colei a referência na resposta :)
Johannes Schaub - litb

E é por isso, senhor, que tem mais alguns pontos do que eu. :)
Arafangion

29

Se, por alguma coincidência maluca, você quiser converter uma sequência de caracteres em um inteiro, você também pode fazer isso!

char *num = "1024";
int val = atoi(num); // atoi = ASCII TO Int

valagora é 1024. Aparentemente atoi()está bem, e o que eu disse sobre isso antes só se aplica a mim (no OS X (talvez (insira a piada do Lisp aqui))). Ouvi dizer que é uma macro que mapeia aproximadamente para o próximo exemplo, que usa strtol()uma função de uso mais geral para fazer a conversão:

char *num = "1024";
int val = (int)strtol(num, (char **)NULL, 10); // strtol = STRing TO Long

strtol() funciona assim:

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

Ele é convertido *strem um long, tratando-o como se fosse um basenúmero base . Se **endptrnão for nulo, ele contém o primeiro caractere diferente de dígito strtol()encontrado (mas quem se importa com isso).


Não há problemas de thread com atoi (não tem dados estáticos) e não está obsoleto. Na verdade, é funcionalmente equivalente a: #define atoi (x) (int) (strtol ((x), NULL, 10)
Evan Teran

5
O problema com atoi é que ele usa 0 como um valor "não é possível encontrar um número aqui", então atoi ("0") e atoi ("um") retornam 0. Se isso não funcionar para o que você ' se estiver usando, procure strtol () ou sscanf ().
David Thornley,

A outra vantagem do strtol, claro, é que você pode precisar ler outras coisas da mesma string que vem depois do número.
dia

@EvanTeran Infelizmente, se você executar o Visual Studio, receberá um aviso de depreciação (e não compilará sem ser desabilitado). VS agora recomenda itoa_s().
Simon

7

Subtraia char '0' ou int 48 assim:

char c = '5';
int i = c - '0';

Explicação: Internamente, funciona com valor ASCII . Na tabela ASCII, o valor decimal do caractere 5 é 53 e 0 é 48 . Então 53 - 48 = 5

OU

char c = '5';
int i = c - 48; // Because decimal value of char '0' is 48

Isso significa que se você deduzir 48 de qualquer caractere numérico, ele converterá o inteiro automaticamente.


6
char numeralChar = '4';
int numeral = (int) (numeralChar - '0');

numeralChar - '0'já é do tipo int, então você não precisa do elenco. Mesmo se não fosse, o gesso não é necessário.
Alok Singhal

Huh, sim, isso coagiria, não é? Talvez Java tenha colorido minhas percepções. Ou talvez eu esteja completamente enganado e isso até coagiria em Java. :)
Kevin Conner,

5

Para converter o dígito do caractere em um inteiro correspondente. Faça como mostrado abaixo:

char c = '8';                    
int i = c - '0';

A lógica por trás do cálculo acima é brincar com os valores ASCII. O valor ASCII do caractere 8 é 56, o valor ASCII do caractere 0 é 48. O valor ASCII do inteiro 8 é 8.

Se subtrairmos dois caracteres, a subtração acontecerá entre ASCII de caracteres.

int i = 56 - 48;   
i = 8;

Por que eu sou o único a votar a favor disso? A explicação é tão simples e informativa: +1:
Brandon Benefield

0

Se for apenas um único caractere 0-9 em ASCII, subtrair o valor do caractere ASCII zero do valor ASCII deve funcionar bem.

Se você deseja converter números maiores, faça o seguinte:

char *string = "24";

int value;

int assigned = sscanf(string, "%d", &value);

** não se esqueça de verificar o status (que deve ser 1 se funcionou no caso acima).

Paulo.


0
char chVal = '5';
char chIndex;

if ((chVal >= '0') && (chVal <= '9')) {

    chIndex = chVal - '0';
}
else 
if ((chVal >= 'a') && (chVal <= 'z')) {

    chIndex = chVal - 'a';
}
else 
if ((chVal >= 'A') && (chVal <= 'Z')) {

    chIndex = chVal - 'A';
}
else {
    chIndex = -1; // Error value !!!
}

0

Quando preciso fazer algo assim, pré-preparo um array com os valores que desejo.

const static int lookup[256] = { -1, ..., 0,1,2,3,4,5,6,7,8,9, .... };

Então a conversão é fácil

int digit_to_int( unsigned char c ) { return lookup[ static_cast<int>(c) ]; }

Essa é basicamente a abordagem adotada por muitas implementações da biblioteca ctype. Você pode adaptar isso trivialmente para funcionar com dígitos hexadecimais também.


Isso parece extremamente ineficiente para converter um único dígito decimal (ou octal). Se a parte relevante de sua tabela de pesquisa não estiver no cache L1, você vai gastar vários ciclos para puxá-la apenas para obter um valor. Francamente, tendo a duvidar que isso seja uma boa ideia se você estiver convertendo uma grande quantidade de dígitos, mas você teria que medir isso. É muito mais competitivo para hex, é claro.
dfeuer

0

Verifique isso,

char s='A';

int i = (s<='9')?(s-'0'):(s<='F')?((s-'A')+10):((s-'a')+10);

para apenas 0,1,2, ...., E, F.


0

Basta usar a atol()função:

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

int main() 
{
    const char *c = "5";
    int d = atol(c);
    printf("%d\n", d);

}

0

Se o seu dígito for, digamos, '5'em ASCII, ele será representado como o número binário 0011 0101(53). Cada dígito tem os quatro bits mais altos 0011e os 4 bits mais baixos representam o dígito em bcd. Então você apenas faz

char cdig = '5';
int dig = cdig & 0xf; // dig contains the number 5

para obter os 4 bits mais baixos, ou, o que é igual, o dígito. Em asm, ele usa andoperação em vez de sub(como nas outras respostas).


'5'é 53 ( 00110101)
eyllanesc de

@eyllanesc No começo foi um 4. Obrigado. Editado.
Garmekain de

0

Aqui estão as funções auxiliares que permitem converter dígito em char para int e vice-versa:

int toInt(char c) {
    return c - '0';
}

char toChar(int i) {
    return i + '0';
}

-2

use a função: atoi para array para inteiro, atof para array para tipo float; ou

char c = '5';
int b = c - 48;
printf("%d", b);

Várias respostas já abordaram isso. Isso não adiciona nada que já não tenham abordado.
ShadowRanger

-3

Você o lançaria em um int (ou float ou double ou o que quer que você queira fazer com ele) e o armazenaria em outra variável.

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.