Usando scanf para aceptar la entrada del usuario

6 minutos de lectura

Usando scanf para aceptar la entrada del usuario
hormiga2009

CCG 4.4.2

Estaba leyendo un artículo sobre scanf. Personalmente, nunca he comprobado el código de retorno de un scanf.

#include <stdio.h>

int main(void)
{
  char buf[64];
  if(1 == scanf("%63s", buf))
  {
    printf("Hello %s\n", buf);
  }
  else
  {
    fprintf(stderr, "Input error.\n");
  }
  return 0;
}

Me pregunto qué otras técnicas hacen los programadores experimentados cuando usan scanf cuando quieren obtener información del usuario. ¿O usan otra función o escriben la suya propia?

Gracias por cualquier sugerencia,

EDITAR =========

#include <stdio.h>

int main(void)
{
    char input_buf[64] = {0};
    char data[64] = {0};

    printf("Enter something: ");
    while( fgets(input_buf, sizeof(input_buf), stdin) == NULL )
    {
    /* parse the input entered */
    sscanf(input_buf, "%s", data);
    }

    printf("Input [ %s ]\n", data);

    return 0;
}

Creo que la mayoría de los programadores están de acuerdo en que scanf es malo, y la mayoría está de acuerdo en usar fgets y sscanf. Sin embargo, puedo usar fgets para leer la entrada. Sin embargo, si no sé qué ingresará el usuario, ¿cómo sé qué analizar? Por ejemplo, como si el usuario ingresara su dirección, que contendría números y caracteres y en cualquier orden.

  • Nunca verificar el código de retorno de ninguna de las rutinas de entrada siempre es extremadamente dudoso: debe tener suerte. La respuesta corta es “No uso scanf() o fscanf(); ocasionalmente uso sscanf() pero andad con cautela”.

    –Jonathan Leffler

    27 de enero de 2010 a las 4:12

  • Después de actualizar mi respuesta. ¿Cómo usaría normalmente sscanf para analizar los datos? ¿Si no está seguro de qué datos ingresará el usuario? Gracias.

    – hormiga2009

    27 de enero de 2010 a las 11:33

1646969827 839 Usando scanf para aceptar la entrada del usuario
jamesdlin

no usar scanf directamente. Es sorprendentemente difícil de usar. Es mejor leer una línea completa de entrada y luego analizarla (posiblemente con sscanf).

Lea esta entrada (y las entradas a las que hace referencia) de las preguntas frecuentes de comp.lang.c:
http://c-faq.com/stdio/scanfprobs.html

Editar: Bien, para abordar su pregunta adicional de su propia edición: si permite la entrada no estructurada, tendrá que intentar analizar la cadena de varias maneras hasta que encuentre una que funcione. Si no puede encontrar una coincidencia válida, debe rechazar la entrada y volver a preguntar al usuario, probablemente explicando en qué formato desea que esté la entrada.

Para algo más complicado, probablemente sería mejor usar una biblioteca de expresiones regulares o incluso usar juegos de herramientas dedicados lexer/parser (por ejemplo, flex y bison).

  • Hola, he actualizado mi respuesta. ¿Pero no estoy seguro del análisis usando sscanf? Gracias.

    – hormiga2009

    27 de enero de 2010 a las 6:12

1646969828 124 Usando scanf para aceptar la entrada del usuario
Juan Bode

no uso scanf() para entrada de usuario interactiva; Leo todo como texto usando fgets()luego analice la entrada según sea necesario, usando strtol() y strtod() para convertir texto a valores numéricos.

Un ejemplo de donde scanf() Falls down es cuando el usuario ingresa un valor numérico incorrecto, pero la parte inicial es válida, algo como lo siguiente:

if (scanf("%d", &num) == 1)
{
  // process num
}
else
{
  // handle error
}

Si el usuario escribe “12e4”, scanf() convertirá y asignará con éxito el “12” a num, dejando “e4” en el flujo de entrada para estropear una lectura futura. los completo la entrada debe ser tratada como falsa, pero scanf() no puedo detectar ese tipo de error. OTOH, si hago algo como:

if (fgets(buffer, sizeof buffer, stdin))
{
  int val;
  char *chk;
  val = (int) strtol(buffer, &chk, 10);
  if (!isspace(*chk) && *chk != 0)
  {
    // non-numeric character in input; reject it completely
  }
  else
  {
    // process val
  }
}

Puedo detectar el error en la entrada y rechazarlo antes de usar cualquier parte del mismo. Esto también hace un mejor trabajo al no dejar basura en el flujo de entrada.

scanf() es una gran herramienta si puede garantizar que su entrada siempre esté bien formada.

  • Hola. Digamos que desea que el usuario ingrese su dirección. Que tendría números y letras. Puede leer la entrada usando fgets. Pero, ¿cómo analizaría la entrada? Creo que podrías simplemente leerlo en un búfer usando fgets y eso sería todo. No puedo ver cómo usarías sscanf para esto. Gracias.

    – hormiga2009

    27 de enero de 2010 a las 15:41

  • Trataría una dirección postal como todo texto, posiblemente dividido en varios campos (dirección, nombre de la calle, ciudad, estado, código postal, etc.). Cuándo y cómo lo tokenizaría dependería de la aplicación (por ejemplo, si necesitara buscar registros según el código postal o el nombre de la calle o algo así). Si todo lo que necesito hacer es almacenarlo para mostrarlo más tarde, probablemente ni siquiera me molestaría en tokenizarlo.

    – Juan Bode

    27 de enero de 2010 a las 19:37

scanf() tiene problemas, ya que si se espera que un usuario escriba un número entero, y en su lugar escribe una cadena, a menudo el programa falla. Esto se puede solucionar leyendo todas las entradas como una cadena (use getchar()) y luego convirtiendo la cadena al tipo de datos correcto.

/* example one, to read a word at a time */
#include <stdio.h>
#include <ctype.h>
#define MAXBUFFERSIZE   80

void cleartoendofline( void );  /* ANSI function prototype */

void cleartoendofline( void )
{
    char ch;
    ch = getchar();
    while( ch != '\n' )
        ch = getchar();
}

main()
{
    char    ch;                     /* handles user input */
    char    buffer[MAXBUFFERSIZE];  /* sufficient to handle one line */
    int     char_count;             /* number of characters read for this line */
    int     exit_flag = 0;
    int     valid_choice;

    while( exit_flag  == 0 ) {
        printf("Enter a line of text (<80 chars)\n");
        ch = getchar();
        char_count = 0;
        while( (ch != '\n')  &&  (char_count < MAXBUFFERSIZE)) {
            buffer[char_count++] = ch;
            ch = getchar();
        }
        buffer[char_count] = 0x00;      /* null terminate buffer */
        printf("\nThe line you entered was:\n");
        printf("%s\n", buffer);

        valid_choice = 0;
        while( valid_choice == 0 ) {
            printf("Continue (Y/N)?\n");
            scanf(" %c", &ch );
            ch = toupper( ch );
            if((ch == 'Y') || (ch == 'N') )
                valid_choice = 1;
            else
                printf("\007Error: Invalid choice\n");
            cleartoendofline();
        }
        if( ch == 'N' ) exit_flag = 1;
    }
}

Hago una llamada de bucle fgets hasta que se lee el final de la línea y luego llamo a sscanf para analizar los datos. Es una buena idea comprobar si sscanf llega al final de la línea de entrada.

rara vez uso scanf. La mayoría de las veces, uso fgets() para leer datos como una cadena. Entonces, dependiendo de la necesidad, puedo usar sscanf()u otras funciones como strto* familia de funciones, str*chr()etc., para obtener datos de la cadena.

si uso scanf() o fgets() + sscanf()I siempre verifique los valores de retorno de las funciones para asegurarse de que hicieron lo que yo quería que hicieran. yo tampoco uso strtok() tokenizar cadenas, porque creo que la interfaz de strtok() está roto.

¿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