Tengo una función scanf que toma un número entero 1, 2 o 0. Mi declaración predeterminada volverá a un bucle si no hay una entrada de estos números enteros. Si se ingresa un carácter, el caso predeterminado aún funciona, muestra un error y regresa a la pantalla principal. Mi pregunta es si debería usar otro ciclo while para verificar la función scanf en busca de un número entero, o si está bien mantener la declaración predeterminada que regresará para cualquier entrada no válida.
int main(int argc, char* argv[]) { int value; value = length_orWeight(); while (value != 0) { value = length_orWeight(); } return 0; } int length_orWeight(void) { int choice; printf("\nWhat would you like to convert?\n0.End Program 1.Lengths 2.Weights: "); scanf("%d", &choice); clear_keyboard_buffer(); switch (choice) { case 1: convert_lengths(); return 1; case 2: convert_weights(); return 2; case 0: return 0; default: printf("\nError: You must enter 0, 1, or 2.\n"); return 3; } }No verificar el valor de retorno de scanf es inadecuado.
El estándar C no especifica qué sucede con los objetos a los que no se les asignan valores porque la entrada finalizó antes de tiempo (como cuando se encontró un carácter que no coincide, se encontró un final de archivo o se produjo un error de entrada). Un comportamiento común puede ser que scanf deje el objeto ( choice ) sin cambios. Si esto ocurre en su primera ejecución de scanf , permanecerá sin inicializar. Sin embargo, como el estándar no define lo que hace scanf a este respecto, son posibles otros comportamientos. Por ejemplo, una implementación rudimentaria de scanf podría, al comenzar a trabajar en %d , inicializar la choice a cero, anticipándose a la construcción de un número dígito por dígito. Cuando luego lee un carácter y encuentra algo que no sea un dígito que ingresó el usuario, podría terminar con un valor de retorno que indica que no se realizó ninguna conversión, con la choice aún establecida en cero.
Si scanf no devuelve un valor que indica que se completó una conversión que asignó un valor a un objeto que le pasó, no sabe qué valor hay en ese objeto, incluso si inicializó el objeto antes de llamar a scanf . Por lo tanto, antes de usar el objeto, debe verificar el valor de retorno de scanf .
Eric Postpischil afirmó claramente que es necesario verificar el valor de retorno de scanf , pero no señaló el hecho de que es una función muy mala para leer la entrada del usuario . Mejor usa fgets y sscanf :
// Reads one line char *scanline(char *line, size_t size, FILE *istream) { if (!fgets(line, size, istream)) // Input failed return NULL; // Replace newline with null-terminator size_t nl = strcspn(line, "\n"); line[nl] = '\0'; return line; } // Reads an int bool scanint(int *i, FILE* istream) { char buffer[255]; if (!scanline(buffer, sizeof buffer, istream)) return false; if (sscanf(buffer, "%d", i) != 1) return false; return true; } Además, asegúrese de que clear_keyboard_buffer() no sea fflush(stdin) :
void clear_keyboard_buffer(void) { scanf("%*[^\n]"); // Read and discard everything until hitting a newline. }Así es como se vería su código:
int length_orWeight(void) { int choice; printf("\nWhat would you like to convert?\n0.End Program 1.Lengths 2.Weights: "); while (!scanint(&choice, stdin)) { printf("Please enter a valid number: "); }; // clear_keyboard_buffer(); // No longer necessary switch (choice) { case 1: //convert_lengths(); return 1; case 2: //convert_weights(); return 2; case 0: return 0; default: printf("\nError: You must enter 0, 1, or 2.\n"); return 3; } } int main(int argc, char* argv[]) { int value; value = length_orWeight(); while (value != 0) { value = length_orWeight(); } }