Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: UsuarioZ en 16 Noviembre 2019, 02:12 am



Título: Duda sobre scanf
Publicado por: UsuarioZ en 16 Noviembre 2019, 02:12 am
Si pido un entero (lo especifico como %d) e ingreso una letra o algo que no sea un entero empieza como una recursion infinita.

¿Como puedo evitar esto en C?


Título: Re: Duda sobre scanf
Publicado por: K-YreX en 16 Noviembre 2019, 03:27 am
Si no estás seguro del tipo de dato que va a introducir el usuario por teclado deberías usar la función <fgets()> y almacenar la entrada en un <char[]> para después validarlo tú internamente.


Título: Re: Duda sobre scanf
Publicado por: ThunderCls en 18 Noviembre 2019, 01:29 am
Para entender cual es el problema primero debes entender como funciona scanf. Esta funcion trabaja con un buffer de entrada o lo que es lo mismo un espacio en memoria de donde obtendra su contenido. Dicho buffer puede provenir de teclado, fichero, pipe, etc (stdin). Luego la funcion scanf intenta leer el buffer segun le especificas en el formato y una vez lee satisfactoriamente, el contenido del buffer leido es consumido. El problema viene cuando scanf no es capaz de leer el buffer como le haz indicado, entonces la funcion falla y el contenido del buffer se queda intacto. En tu caso le dices a scanf que debe leer un entero "%d" pero esta falla al encontrarse con un caracter, por lo que la funcion regresa sin haber modificado el buffer de entrada. Ahora ese caracter estara en ese buffer hasta que "alguien" lo elimine o se limpie el buffer por completo, lo que hace que tu scanf se siga llamando indefinidamente.
Luego de esta teoria, la solucion al problema se reduce a simplemente asegurarte que el buffer es limpiado si tu scanf falla para evitar un loop infinito. Una posible solucion seria:

Código
  1. #define ENTER '\n'
  2. #define CORRECT_INPUT_FLAG 2
  3. char ret = '\0';
  4. int number = 0;
  5.  
  6. if(scanf("%d%c", &number, &ret) != CORRECT_INPUT_FLAG || ret != ENTER)
  7. {
  8.    printf("Entrada invalida\n");
  9.    while (getchar() != ENTER) { } // limpia el buffer de caracteres invalidos
  10. }

Por otra parte scanf es inseguro, impredecible y dificil de manejar, una mejor solucion seria usar fgets()/getline() y sscanf() si necesitas parsear el contenido a variables.
Saludos