Discussion:
COMO EVITAR BUCLE INFINITO, CON SCANF %d
(demasiado antiguo para responder)
HADES
2004-01-05 02:02:56 UTC
Permalink
estoy haciendo un programa con un menu:
1. comer
2. dormir
3. correr... (ejemplo)

controlo que solo me deje introducir los números que esté dentro del
rango que deseo con un do{ }while() pero el problema esta que cuando
se introduce una letra o otra cosa que no sea un número, me entra en
un bucle infinito ¿alguien podría ayudarme?; gracias;
Fernando Arbeiza
2004-01-05 07:46:14 UTC
Permalink
Post by HADES
controlo que solo me deje introducir los números que esté dentro del
rango que deseo con un do{ }while() pero el problema esta que cuando
se introduce una letra o otra cosa que no sea un número, me entra en
un bucle infinito ¿alguien podría ayudarme?; gracias;
Es fácil, scanf toma la información del flujo de entrada. Como no tiene
el formato que espera, la vuelve a dejar ahí. Luego en el siguiente
bucle vuelve a pasar exactamente lo mismo.

Se me ocurren dos posibilidades:

- Utilizar getchar() e ir tratando carácter a carácter (si cada
elemento del menú se accede con un sólo carácter).

- Utilizar fgets() y después interpretar la línea. Puedes hacerlo
con sscanf() o, ya que utilizas números, mejor con strtol() ó
strtoul().

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
jakala
2004-01-05 21:16:06 UTC
Permalink
suena a que el problema es que lees con el scanf un tipo int.
--> scanf("%d", &opcion);

Yo lo que suelo hacer es leer con el scanf en un array char, y luego como
dice Fernando,
interpretar esa lectura.

algo asi:

char cadena[2];
int opcion;
... // cosas del menu

scanf("%s", cadena);
opcion = atoi(cadena);

la funcion "atoi" interpreta el numero que se ha introducido en la cadena.
Si la cadena
contiene letras, te devuelve un 0 (ojo con eso).
Hay otras funciones para interpretar... usa la que mas te guste :P
Jakala
Post by Fernando Arbeiza
Post by HADES
controlo que solo me deje introducir los números que esté dentro del
rango que deseo con un do{ }while() pero el problema esta que cuando
se introduce una letra o otra cosa que no sea un número, me entra en
un bucle infinito ¿alguien podría ayudarme?; gracias;
Es fácil, scanf toma la información del flujo de entrada. Como no tiene
el formato que espera, la vuelve a dejar ahí. Luego en el siguiente
bucle vuelve a pasar exactamente lo mismo.
- Utilizar getchar() e ir tratando carácter a carácter (si cada
elemento del menú se accede con un sólo carácter).
- Utilizar fgets() y después interpretar la línea. Puedes hacerlo
con sscanf() o, ya que utilizas números, mejor con strtol() ó
strtoul().
Un saludo.
--
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
Fernando Arbeiza
2004-01-05 22:53:13 UTC
Permalink
Post by jakala
char cadena[2];
int opcion;
... // cosas del menu
scanf("%s", cadena);
¿Qué pasa en este caso si introduces una línea con más de un carácter?

Utilizar scanf() de esa manera es tan peligroso como usar gets(). Puedes
escribir fuera de la memoria asignada a nada que te descuides.
Post by jakala
opcion = atoi(cadena);
la funcion "atoi" interpreta el numero que se ha introducido en la cadena.
Si la cadena
contiene letras, te devuelve un 0 (ojo con eso).
Ese es el problema de atoi() que no detecta errores, por eso
(preferencia personal), prefiero strtol.

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
jakala
2004-01-06 23:58:04 UTC
Permalink
y que tal si usaramos:
scanf("%2s", cadena);

es cierto que, de no indicar el n de caracteres a leer, puedes escribir en
zonas de memoria no asignada.
en el caso de asignar el n de caracteres, no ocurre el problema.
ahora bien, si incluimos espacios al principio, y al final, seguimos
teniendo problemas.

de todas formas, si no recuerdo mal, antes usaba fgets.

es como el gets, pero indicas el tamaño de lectura y el fichero de origen
(normalmente stdin).

Jakala
Post by Fernando Arbeiza
Post by jakala
char cadena[2];
int opcion;
... // cosas del menu
scanf("%s", cadena);
¿Qué pasa en este caso si introduces una línea con más de un carácter?
Utilizar scanf() de esa manera es tan peligroso como usar gets(). Puedes
escribir fuera de la memoria asignada a nada que te descuides.
Post by jakala
opcion = atoi(cadena);
la funcion "atoi" interpreta el numero que se ha introducido en la cadena.
Si la cadena
contiene letras, te devuelve un 0 (ojo con eso).
Ese es el problema de atoi() que no detecta errores, por eso
(preferencia personal), prefiero strtol.
Un saludo.
--
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
Fernando Arbeiza
2004-01-07 07:09:03 UTC
Permalink
Post by jakala
scanf("%2s", cadena);
En este caso tiene que ser:

scanf("%1s", cadena);

Ya que cadena es de 2 bytes de longitud. Funciona, pero tiene el
problema de que el número de caracteres no puede especificarse con una
variable. A no ser que utilices algo así:

#define LONGITUD 2
#define SCANF_LONG "1"

/* ... */

char cadena[LONGITUD];

scanf("%" SCANF_LONG "s", cadena);

/* ... */

Mucho más cómodo fgets, como indicas después.

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
Loading...