Qual é a diferença entre a minha atoi (chamadas)?
Pergunta
Eu tenho um grande número armazenado em uma corda e tentar extrair um único dígito. Mas quais são as diferenças entre as chamadas?
#include <iostream>
#include <string>
int main(){
std::string bigNumber = "93485720394857230";
char tmp = bigNumber.at(5);
int digit = atoi(&tmp);
int digit2 = atoi(&bigNumber.at(5))
int digit3 = atoi(&bigNumber.at(12));
std::cout << "digit: " << digit << std::endl;
std::cout << "digit2: " << digit2 << std::endl;
std::cout << "digit3: " << digit3 << std::endl;
}
Isto produzirá o seguinte resultado.
dígitos: 7
digit2: 2147483647
digit3: 57230
O primeiro é o resultado desejado. A segunda parece-me ser um número aleatório, o que eu não posso encontrar na seqüência. O terceiro é o fim da cadeia, mas não apenas um único dígito como eu esperava, mas a partir do índice de 12 a extremidade da corda. Alguém pode explicar as diferentes saídas para mim?
EDIT:? Será que isso é uma solução aceitável
char tmp[2] = {bigNumber.at(5), '\0'};
int digit = atoi(tmp);
std::cout << "digit: " << digit << std::endl;
Solução
É tudo mais ou menos explicável.
int main(){
std::string bigNumber = "93485720394857230";
Esta linha copia o caráter único '5' para a variável de caráter. espera atoi
irá converter isso corretamente. atoi
que o parâmetro de string é uma válida 0 string terminada. &tmp
apenas um ponteiro para a variável de caráter - o comportamento desta chamada é indefinida já que a memória imediatamente após o personagem na memória é desconhecida. Para ser exato, você teria que criar uma cadeia nula terminada e passar isso em. *
char tmp = bigNumber.at(5);
int digit = atoi(&tmp);
Esta linha recebe um ponteiro para o caractere na posição 5 na cadeia. Isto acontece por ser um ponteiro para a string grande número original acima - assim o parâmetro da sequência de olhares atoi
como a string "5720394857230". atoi
vai claramente oveflow tentando transformar isso em um inteiro desde há inteiro de 32 bit irá realizar isso.
int digit2 = atoi(&bigNumber.at(5))
Esta linha recebe um ponteiro para a string na posição 12. O parâmetro para atoi
é a string
"57230". Esta é convertido para o número inteiro 57230 corretamente.
int digit3 = atoi(&bigNumber.at(12));
... }
Uma vez que você estiver usando C ++, existem métodos mais agradável para cordas converter de caracteres em números inteiros. Um que eu sou parcial é o impulso lexical_cast biblioteca. Você poderia usá-lo como este:
char tmp = bigNumber.at(5);
// convert the character to a string then to an integer
int digit = boost::lexical_cast<int>(std::string(tmp));
// this copies the whole target string at position 5 and then attempts conversion
// if the conversion fails, then a bad_lexical_cast is thrown
int digit2=boost::lexical_cast<int>(std::string(bigNumber.at(5)));
* A rigor, atoi
fará a varredura através dos caracteres numéricos até que um não-numérico é encontrado. é claramente indefinido-lo quando ele iria encontrar um e que ele vai fazer quando lê sobre locais de memória inválidos.
Outras dicas
Eu sei porque o segundo número é exibido.
Se o valor correto está fora do intervalo de valores representáveis,
INT_MAX
ou INT_MIN é retornado.
2147483647 é INT_MAX
bigNumber.at()
não retornar uma nova string com um único personagem, mas o endereço de um caractere na seqüência. Assim, a segunda chamada é realmente:
atoi("720394857230")
que faz com que o algoritmo interno para estouro.
Além disso, a primeira chamada é muito perigoso, uma vez que depende do valor (aleatório) na memória (&tmp)+1
.
Você tem que alocar uma string com dois caracteres, atribuir o caráter único de bigNumber.at()
ao primeiro e \0
para o segundo e, em seguida, chamar atoi()
com o endereço da string temporário.
O argumento para atoi
deve ser uma string terminada em zero.
at
Função dá ponteiro para caractere na string. Função converte atoi
string para int, não apenas um caractere.