c++ - solo - Cómo validar la entrada usando scanf
validar que solo ingrese numeros en c++ (6)
¿Cómo puedo validar la entrada del usuario utilizando scanf? En este momento tengo algo como esto, pero no funciona.
NOTA: Tengo el atoi solo para validar que la validación de scanf funciona.
scanf("%[0987654321.-]s",buf);
i = atoi(buf);
if(i)
index = i;
"buf" necesita ser un puntero. Parece que estás pasando por valor.
Lo que especificó en el primer argumento para scanf
son especificadores de conversión . scanf
intentará convertir la entrada al formato, pero a veces puede que te sorprenda con qué coincidirá :)
La primera comprobación que debe hacer es en el valor de retorno de scanf (le dará el número de entradas que coinciden). Si no obtiene el número que está esperando, entonces sabrá que algo está mal con la entrada. En tu caso, debería ser 1.
if( scanf("%[0987654321.-]s", buf) == 1 )
{
if( sanit_check( buf ) )
{
/* good input */
}
else
{
/* invalid input */
}
}
else
{
/* invalid input */
}
Más allá de eso, tendrá que hacer sus propios controles de cordura en la conversión que solicitó scanf
para hacer.
Mi enfoque sería leer la entrada del usuario en una cadena y luego convertirla a long usando strtol()
. strtol()
devuelve el puntero al primer carácter en la cadena de entrada que no pudo procesar, por lo que al marcar este carácter sabrá si se analizó la cadena completa, así:
char *string;
char *endptr;
long result;
scanf("%as", string);
errno = 0;
result = strtol(string, &endptr, 10);
if (ERANGE == errno)
printf("Input number doesn''t fit into long/n");
else if (*endptr)
printf("%s is not a valid long number - it contains invalid char %c/n",
string, *endptr);
else
printf("Got %ld/n", result);
En este fragmento, scanf()
recibe instrucciones de asignar automáticamente una string
suficientemente grande usando el modificador de formato "a" (esta es la extensión de GNU). Si no está en GNU, asigne la string
manualmente y limite el tamaño máximo en formato scanf()
.
Este enfoque permite un mejor manejo de errores.
Si estás tratando de leer solo un número, usa:
int i;
scanf( "%d", &i );
Si necesita hacer comprobaciones más complicadas, tendrá que hacerlo usted mismo. Scanf no lo hará por usted.
El uso de scanf()
suele ser una mala idea para la entrada del usuario, ya que la falla deja el puntero del FILE
en una posición desconocida. Esto se debe a que scanf
significa "escaneo formateado" y hay poco más sin formatear que la entrada del usuario.
Yo sugeriría usar fgets()
para obtener una línea, seguido de sscanf()
en la cadena para verificarlo y procesarlo.
Esto también le permite verificar la cadena de caracteres que desee (ya sea mediante un bucle o con una expresión regular), algo que la familia de funciones de scanf
no es realmente adecuada.
A modo de ejemplo, el uso de scanf()
con un "%d"
o "%f"
se detendrá en el primer carácter que no sea numérico, por lo que no detectará errores finales como "127hello"
, que solo le dará 127. Y usando con un %s
no limitado solo pide un desbordamiento de búfer.
Si realmente debe usar el especificador de formato []
(en scanf
o sscanf
), no creo que deba seguirse por s
.
Y, para una solución de entrada robusta usando ese consejo, mira aquí . Una vez que tiene una línea de entrada como una cadena, puede sscanf
el contenido de su corazón.
Parece que quiere validar una cadena como entrada. Depende de si desea validar que su cadena contiene un doble o un int. La siguiente comprobación de un doble (espacios en blanco iniciales y finales está permitido).
bool is_double(char const* s) {
int n;
double d;
return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}
sscanf
devolverá los elementos convertidos (sin ''% n''). n
ajustará a la cantidad de caracteres de entrada procesados. Si se procesó toda la entrada, s [n] devolverá el carácter 0 de terminación. El espacio entre los dos especificadores de formato da cuenta del espacio en blanco posterior opcional.
La siguiente comprobación de un int, las mismas técnicas utilizadas:
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
Hubo una pregunta al respecto, que incluye también más formas C ++ ''ish para hacer esto, como el uso de secuencias de cadenas y funciones de boost, como lexical_cast y así sucesivamente. En general, deberían preferirse a las funciones como scanf, ya que es muy fácil olvidar pasar un ''%'' a scanf, o alguna dirección. scanf no lo reconocerá, sino que hará cosas arbitrarias, mientras que lexical_cast, por ejemplo, lanzará una excepción si algo no está bien.