¿Por qué scanf se atasca en un bucle infinito en una entrada no válida? [duplicate]

4 minutos de lectura

avatar de usuario
Dchris

En la línea 5 leí un número entero y isint obtiene 1 si lee un número entero o 0 si no es un número entero. Si isint es 0 Tengo un bucle que le pide al usuario que dé un número entero y lo leo hasta que el usuario da un número entero. Intento este código dando un carácter en lugar de un número entero pero tengo un ciclo infinito. El programa simplemente no espera para dar una nueva entrada. ¿Qué pasa con mi código?

#include <stdio.h>

int main(void) {

  int arg1;
  //int arg2;
  int attacknum = 1;
  int isint = 1;

  //printf("Insert argument attacks and press 0 when you have done this.\n");
  printf("Attack %d\n", attacknum);
  attacknum++;
  printf("Give attacking argument:");
  isint = scanf("%d", &arg1);  //line 5

  while(isint == 0){
    printf("You did not enter a number. Please enter an argument's number\n");
    isint = scanf("%d", &arg1);
    printf("is int is %d\n", isint);
  }
  return 0;
}

  • ¿Cuál es el resultado de printf(“is int is %d\n”,isint)?

    – Xonar

    2 de junio de 2013 a las 11:57

  • Proporcione la salida de la consola de su escenario.

    – zsawyer

    2 de junio de 2013 a las 11:58

avatar de usuario
piscina

Como otros han mencionado, si scanf no puede analizar la entrada, la deja sin escanear.

Generalmente scanf es una mala elección para la entrada interactiva debido a este tipo de comportamiento y porque no coincide con la interfaz de línea a línea experimentada por el usuario.

Es mejor leer una línea en un búfer usando fgets. Luego analiza esa línea usando sscanf. Si no le gusta la entrada, deseche toda la línea y lea otra.

Algo como esto:

#include <stdio.h>

int main(void)
{
  char line[256];

  int arg1;
  int isint;

  while (1) {
    printf("Give attacking argument:");
    fgets(line, sizeof line, stdin);
    isint = sscanf(line, "%d",&arg1);
    if (isint) break;

    printf("You did not enter a number.Please enter an argument's number\n");
  }

  printf("Thanks for entering %d\n", arg1);

  return 0;
}

(Para el código de producción, querrá manejar líneas largas, verificar los códigos de retorno, también verificar si hay basura después del número, etc.)

En realidad, un enfoque aún mejor sería No utilice scanf si solo quiere leer un número entero, y en su lugar usa strtol. Eso le da un puntero útil al carácter justo después del número, y puede verificar que sea un espacio en blanco o nulo.

  • Esto seguirá aceptando entradas como 123ab como 123. Es una buena idea usar un ciclo for para buscar caracteres no válidos dentro de la línea, vea la misma pregunta aquí: stackoverflow.com/questions/20829672/…

    – ilgaar

    31 de diciembre de 2013 a las 13:05


  • Detectar si hay basura al final es una buena idea. Hacerlo escaneando manualmente la cadena, como en esa pregunta, es una forma muy larga y poco elegante de hacerlo. Mejor solo usar strtol lo que le da un puntero al siguiente carácter.

    – piscina

    3 de enero de 2014 a las 19:24

avatar de usuario
bryan olivier

Cuando scanf se enfrenta a un no dígito, no consumirá ninguna entrada y devolverá que se leyeron cero enteros. El no dígito permanecerá en la entrada para la próxima llamada a scanf que se comportará igual que la primera llamada, etc.

En respuesta a su pregunta a continuación. podrías usar fgetc para analizar al menos un carácter, pero esto dará los mensajes de error para cada carácter ya escrito. Por lo general, creo que desea omitir hasta una nueva línea. Para ello podrías utilizar fgets como sugiere Poolie. O podría agregar lo siguiente después scanf.

int ch;
if (isint == 0)
while ((ch = fgetc(stdin)) != EOF && ch != '\n')
{
     /* Skip characters */
}

PD: En tu caso probablemente sea mejor ponerlo justo antes del primero printf en el lazo.

  • ¿Qué sugieres para resolver el problema? ¿Cómo puedo consumir el no dígito?

    – Dchris

    2 de junio de 2013 a las 12:04

  • @Dchris Agregué algunas sugerencias.

    –Bryan Olivier

    2 de junio de 2013 a las 12:16

  • @Dchris ¿Qué investigación ha realizado? ¿Hablas en serio con esa pregunta? ¿Por qué no estás leyendo un libro?

    – autista

    2 de junio de 2013 a las 13:25

  • @poolie: Y otros con edit happy fingers: gracias por arreglar el nombre de la variable, pero también podrías haber hecho un comentario. Sin embargo, tenga en cuenta que este estilo de codificación es intencional, así que no lo cambie.

    –Bryan Olivier

    4 de junio de 2013 a las 9:03

  • Podría haber dejado un comentario, pero la edición parece más simple, hace menos ruido y parece estar en el espíritu de la naturaleza wiki de SO. Y ese estilo de codificación… está bien, puedes elegir, pero es bastante inusual, ¿puedes culparme por pensar que también fue un error tipográfico? No hay necesidad de ser grosero.

    – piscina

    4 de junio de 2013 a las 9:06


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad