Usando scanf para aceptar la entrada del usuario

gcc 4.4.2

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

#include  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 progtwigdores experimentados cuando usan scanf cuando desean obtener información del usuario. ¿O usan otra función o escriben la suya?

Gracias por cualquier sugerencia,

EDITAR =========

 #include  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 progtwigdores están de acuerdo en que scanf es malo, y la mayoría acepta usar fgets y sscanf. Sin embargo, puedo usar fgets para leer en la entrada. Sin embargo, si no sé qué ingresará el usuario, ¿cómo puedo saber qué analizar? Por ejemplo, ¿como si el usuario ingresara su dirección que contendría números y caracteres y en cualquier orden?

No utilice 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) en las preguntas frecuentes de comp.lang.c: http://c-faq.com/stdio/scanfprobs.html

Edición: está bien, para abordar su pregunta adicional de su propia edición: si permite entradas no estructuradas, 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 cualquier cosa más complicada, probablemente sería mejor usar una biblioteca de expresiones regulares o incluso usar kits de herramientas dedicados de lexer / parser (por ejemplo, flex y bison).

No uso scanf() para la entrada interactiva del usuario; Lo leo todo como texto usando fgets() , luego analizo la entrada según sea necesario, usando strtol() y strtod() para convertir texto a valores numéricos.

Un ejemplo de la caída de scanf() es cuando el usuario ingresa un valor numérico incorrecto, pero su parte inicial es válida, como la siguiente:

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

Si el usuario escribe “12e4”, scanf() convertirá y asignará exitosamente “12” a num, dejando “e4” en el flujo de entrada para entorpecer una lectura futura. Toda la entrada debe tratarse como falsa, pero scanf() no puede 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 de él. Esto también hace un mejor trabajo de no dejar basura en el flujo de entrada.

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

scanf () tiene problemas, ya que si se espera que un usuario escriba un entero y escriba una cadena en su lugar, a menudo el progtwig bombardea. Esto se puede superar leyendo todas las entradas como una cadena (use getchar ()) y luego convierta la cadena al tipo de datos correcto.

 /* example one, to read a word at a time */ #include  #include  #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 un bucle de llamada a fgets hasta que se lee el final de la línea, y luego llamo a sscanf para analizar los datos. Es una buena idea verificar si sscanf llega al final de la línea de entrada.

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

Si uso scanf() o fgets() + sscanf() , siempre verifico los valores de retorno de las funciones para asegurarme de que hicieron lo que yo quería que hicieran. Tampoco utilizo strtok() para tokenizar cadenas, porque creo que la interfaz de strtok() está rota.