¿Cómo puedo saber si la función c atoi falló o si fue una cadena de ceros?
Pregunta
Al usar la función atoi
(o strtol
o funciones similares para el caso), ¿cómo puede saber si la conversión de enteros falló o si la cadena C fue ser convertido fue un 0
?
Por lo que estoy haciendo, 0
es un valor aceptable y la cadena C que se está convirtiendo puede contener cualquier número de 0
s. También puede tener espacios en blanco principales.
Solución
Para C ++ 11 y posterior:
La función go-to para la conversión de cadena a entero ahora es stoi
, que toma una cadena
y devuelve un int
, o arroja una excepción en caso de error.
Ya no es necesario el truco detallado istringstream
mencionado en la respuesta aceptada.
(También hay stol
/ stoll
/ stof
/ stod
/ stold
para long
/ long long
/ float
/ double
/ long double
, respectivamente .)
Otros consejos
La función adecuada (siempre y cuando insista en usar funciones de estilo C) es strtol
y el código de conversión puede verse de la siguiente manera
const char *number = "10"; /* for example */
char *end;
long value = strtol(number, &end, 10);
if (end == number || *end != '\0' || errno == ERANGE)
/* ERROR, abort */;
/* Success */
/* Add whatever range checks you want to have on the value of `value` */
Algunas observaciones:
strtol
permite (es decir: salta silenciosamente) espacios en blanco delante del número real. Si desea tratar ese espacio en blanco principal como un error, debe verificarlo usted mismo.
La comprobación de * end! = '\ 0'
asegura que no haya nada después de los dígitos. Si desea permitir otros caracteres después del número real (espacio en blanco?), Esta verificación debe modificarse en consecuencia.
P.S. Agregué la verificación end == number
más tarde para capturar secuencias de entrada vacías. " Todos los espacios en blanco " y "ningún número en absoluto" las entradas habrían sido capturadas por * end! = '\ 0'
solo. Sin embargo, podría tener sentido captar entradas vacías de antemano. En ese caso, la verificación end == number
será / podría ser innecesaria.
Dado que esto está etiquetado c ++ :
template< typename T >
inline T convert(const std::string& str)
{
std::istringstream iss(str);
T obj;
iss >> std::ws >> obj >> std::ws;
if(!iss.eof())
throw "dammit!";
return obj;
}
Desde la página del manual para strtol ():
Si endptr no es NULL, strtol () almacena la dirección del primer inválido carácter en * endptr. Sin embargo, si no hubiera dígitos, strtol () almacena el valor original de nptr en * endptr. (Por lo tanto, si * nptr no es
'\ 0'
pero ** endptr es'\ 0'
en la devolución, toda la cadena era válida.)
Una alternativa a strtol
es sscanf
, aunque es un poco pesado:
const char *numStr = "12345"; // input string
int value;
if(sscanf(numStr, "%d", &value) == 1)
; // parsing succeeded, use value
else
; // error
Sin embargo, esto permite espacios en blanco iniciales en su cadena (lo que puede o no ser deseable), y permite que cualquier cosa rastree el número, por lo que "123abc" sería aceptado y devolvería 123. Si desea tener un control más estricto, vaya con strtol ()
, como AndreyT demuestra .
Ha pasado un tiempo desde que lo hice y C / C ++, pero me parece que la solución (demasiado) simple sería verificar solo la cadena para "0".
int value = atoi(string_number.c_str());
if ( !value && string_number != "0" ) {
// error
} else {
// great success!
}