¿Cuál es la diferencia entre mis llamadas atoi ()?
Pregunta
Tengo un gran número almacenado en una cadena e intento extraer un solo dígito. ¿Pero cuáles son las diferencias entre esas llamadas?
#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;
}
Esto producirá el siguiente resultado.
dígito: 7
digit2: 2147483647
dígito3: 57230
El primero es el resultado deseado. El segundo me parece un número aleatorio, que no puedo encontrar en la cadena. El tercero es el final de la cadena, pero no solo un solo dígito como esperaba, sino desde el índice 12 hasta el final de la cadena. ¿Alguien puede explicarme las diferentes salidas?
EDITAR: ¿Sería una solución aceptable?
char tmp[2] = {bigNumber.at(5), '\0'};
int digit = atoi(tmp);
std::cout << "digit: " << digit << std::endl;
Solución
Todo es más o menos explicable.
int main(){
std::string bigNumber = "93485720394857230";
Esta línea copia el carácter individual '5' en la variable de caracteres. atoi
convertirá esto correctamente. atoi
espera que el parámetro de cadena sea una cadena terminada en 0 válida. & amp; tmp
es solo un puntero a la variable de caracteres: el comportamiento de esta llamada no está definido ya que la memoria que sigue inmediatamente al carácter en la memoria es desconocida. Para ser exactos, tendría que crear una cadena terminada en nulo y pasarla. *
char tmp = bigNumber.at(5);
int digit = atoi(&tmp);
Esta línea obtiene un puntero al carácter en la posición 5 de la cadena. Esto resulta ser un puntero en la cadena de números grandes original anterior, por lo que el parámetro de cadena a atoi
se parece a la cadena "5720394857230". atoi
claramente se desbordará tratando de convertir esto en un entero ya que ningún entero de 32 bits lo mantendrá.
int digit2 = atoi(&bigNumber.at(5))
Esta línea obtiene un puntero en la cadena en la posición 12. El parámetro para atoi
es la cadena
" 57230 " ;. Esto se convierte en el entero 57230 correctamente.
int digit3 = atoi(&bigNumber.at(12));
... }
Dado que está utilizando C ++, existen mejores métodos para convertir cadenas de caracteres en enteros. Una de las que soy parcial es la biblioteca Boost lexical_cast. Lo usarías así:
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)));
* Estrictamente, atoi
escaneará los caracteres numéricos hasta que se encuentre uno no numérico. Está claramente indefinido cuándo encontraría uno y qué hará al leer sobre ubicaciones de memoria no válidas.
Otros consejos
Sé por qué se muestra el segundo número.
Si el valor correcto está fuera del rango de valores representables, se devuelve
INT_MAX
o INT_MIN.
2147483647 es INT_MAX
bigNumber.at ()
no devuelve una nueva cadena con un solo carácter sino la dirección de un carácter en la cadena. Entonces la segunda llamada es en realidad:
atoi("720394857230")
que hace que el algoritmo interno se desborde.
Además, la primera llamada es muy peligrosa ya que depende del valor (aleatorio) en la memoria en (& amp; tmp) +1
.
Debe asignar una cadena con dos caracteres, asignar el carácter único de bigNumber.at ()
al primero y \ 0
al segundo y luego llamar a < code> atoi () con la dirección de la cadena temporal.
El argumento para atoi
debería ser una cadena terminada en cero.
La función en
da el puntero a char en la cadena. La función atoi
convierte la cadena a int, no solo un carácter.