while validar usando salir restaurante programa opciones numeros funciones ejercicios ejemplos dev con ciclo c validation input while-loop scanf

usando - uso apropiado de scanf en un ciclo while para validar entrada



validar numeros en c (4)

Hice este código:

/*here is the main function*/ int x , y=0, returned_value; int *p = &x; while (y<5){ printf("Please Insert X value/n"); returned_value = scanf ("%d" , p); validate_input(returned_value, p); y++; }

la función:

void validate_input(int returned_value, int *p){ getchar(); while (returned_value!=1){ printf("invalid input, Insert Integers Only/n"); getchar(); returned_value = scanf("%d", p); } }

Aunque generalmente funciona muy bien, pero cuando inserto, por ejemplo, "1f1", acepta el "1" y no informa ningún error, y cuando inserta "f1f1f", lo lee dos veces y arruina la segunda lectura / exploración, y así sucesivamente ( es decir, la primera lectura imprime "entrada no válida, inserte enteros solamente" y en lugar de esperar nuevamente para volver a leer la primera lectura del usuario, continúa hasta la segunda lectura y vuelve a imprimir "entrada no válida, inserte enteros solamente" de nuevo ...

Necesita un toque final y leí muchas respuestas pero no pude encontrarlo.


Si está leyendo un flujo de entrada que sabe que es una secuencia de texto, pero que no está seguro solo consiste en enteros, entonces lea cadenas.

Además, una vez que haya leído una cadena y desee ver si se trata de un número entero, use la rutina de conversión de biblioteca estándar strtol() . Al hacer esto, ambos obtienen una confirmación de que se trata de un número entero y lo convierten en un long .

#include <stdbool.h> #include <stdio.h> #include <stdlib.h> bool convert_to_long(long *number, const char *string) { char *endptr; *number = strtol(string, &endptr, 10); /* endptr will point to the first position in the string that could * not be converted. If this position holds the string terminator * ''/0'' the conversion went well. An empty input string will also * result in *endptr == ''/0'', so we have to check this too, and fail * if this happens. */ if (string[0] != ''/0'' && *endptr == ''/0'') return false; /* conversion succesful */ return true; /* problem in conversion */ } int main(void) { char buffer[256]; const int max_tries = 5; int tries = 0; long number; while (tries++ < max_tries) { puts("Enter input:"); scanf("%s", buffer); if (!convert_to_long(&number, buffer)) break; /* returns false on success */ printf("Invalid input. ''%s'' is not integer, %d tries left/n", buffer, max_tries - tries); } if (tries > max_tries) puts("No valid input found"); else printf("Valid input: %ld/n", number); return EXIT_SUCCESS; }

AÑADIDO NOTA : Si cambia la base (el último parámetro a strtol() ) de 10 a cero, obtendrá la característica adicional de que su código convierte números hexadecimales y octales (cadenas que comienzan con 0x y 00 respectivamente) en enteros.


Si no quiere aceptar 1f1 como entrada válida, entonces scanf es la función incorrecta para usar, ya que scanf regresa tan pronto como encuentra una coincidencia.

En su lugar, lea toda la línea y luego verifique si solo contiene dígitos. Después de eso puedes llamar scanf

Algo como:

#include <stdio.h> int validateLine(char* line) { int ret=0; // Allow negative numbers if (*line && *line == ''-'') line++; // Check that remaining chars are digits while (*line && *line != ''/n'') { if (!isdigit(*line)) return 0; // Illegal char found ret = 1; // Remember that at least one legal digit was found ++line; } return ret; } int main(void) { char line[256]; int i; int x , y=0; while (y<5) { printf("Please Insert X value/n"); if (fgets(line, sizeof(line), stdin)) // Read the whole line { if (validateLine(line)) // Check that the line is a valid number { // Now it should be safe to call scanf - it shouldn''t fail // but check the return value in any case if (1 != sscanf(line, "%d", &x)) { printf("should never happen"); exit(1); } // Legal number found - break out of the "while (y<5)" loop break; } else { printf("Illegal input %s", line); } } y++; } if (y<5) printf("x=%d/n", x); else printf("no more retries/n"); return 0; }

Entrada

1f1 f1f1 -3

Salida

Please Insert X value Illegal input 1f1 Please Insert X value Illegal input f1f1 Please Insert X value Illegal input Please Insert X value x=-3

Otro enfoque: evitar scanf

Puede dejar que su función calcule el número y omitir scanf por completo. Podría verse así:

#include <stdio.h> int line2Int(char* line, int* x) { int negative = 0; int ret=0; int temp = 0; if (*line && *line == ''-'') { line++; negative = 1; } else if (*line && *line == ''+'') // If a + is to be accepted line++; // If a + is to be accepted while (*line && *line != ''/n'') { if (!isdigit(*line)) return 0; // Illegal char found ret = 1; // Update the number temp = 10 * temp; temp = temp + (*line - ''0''); ++line; } if (ret) { if (negative) temp = -temp; *x = temp; } return ret; } int main(void) { char line[256]; int i; int x , y=0; while (y<5) { printf("Please Insert X value/n"); if (fgets(line, sizeof(line), stdin)) { if (line2Int(line, &x)) break; // Legal number - break out printf("Illegal input %s", line); } y++; } if (y<5) printf("x=%d/n", x); else printf("no more retries/n"); return 0; }


Tomé @ 4386427 idea y acabo de agregar códigos para cubrir lo que se perdió (espacios iniciales y signo +), lo probé muchas veces y está funcionando perfectamente en todos los casos posibles.

#include<stdio.h> #include <ctype.h> #include <stdlib.h> int validate_line (char *line); int main(){ char line[256]; int y=0; long x; while (y<5){ printf("Please Insert X Value/n"); if (fgets(line, sizeof(line), stdin)){//return 0 if not execute if (validate_line(line)>0){ // check if the string contains only numbers x =strtol(line, NULL, 10); // change the authentic string to long and assign it printf("This is x %d" , x); break; } else if (validate_line(line)==-1){printf("You Have Not Inserted Any Number!.... ");} else {printf("Invalid Input, Insert Integers Only.... ");} } y++; if (y==5){printf("NO MORE RETRIES/n/n");} else{printf("%d Retries Left/n/n", (5-y));} } return 0;} int validate_line (char *line){ int returned_value =-1; /*first remove spaces from the entire string*/ char *p_new = line; char *p_old = line; while (*p_old != ''/0''){// loop as long as has not reached the end of string *p_new = *p_old; // assign the current value the *line is pointing at to p if (*p_new != '' ''){p_new++;} // check if it is not a space , if so , increment p p_old++;// increment p_old in every loop } *p_new = ''/0''; // add terminator if (*line== ''+'' || *line== ''-''){line++;} // check if the first char is (-) or (+) sign to point to next place while (*line != ''/n''){ if (!(isdigit(*line))) {return 0;} // Illegal char found , will return 0 and stop because isdigit() returns 0 if the it finds non-digit else if (isdigit(*line)){line++; returned_value=2;}//check next place and increment returned_value for the final result and judgment next. } return returned_value; // it will return -1 if there is no input at all because while loop has not executed, will return >0 if successful, 0 if invalid input }


En general, opino que es mejor leer todo desde la entrada (dentro del rango de su tamaño de búfer, por supuesto), y luego validar la entrada es de hecho el formato correcto.

En su caso, está viendo errores usando una cadena como f1f1f porque no está leyendo todo el buffer STDIN. Como tal, cuando va a volver a llamar a scanf(...) , todavía hay datos dentro de STDIN, por lo que se lee primero en lugar de pedir al usuario que ingrese más entradas. Para leer todo STDIN, debe hacer algo de lo siguiente (parte del código tomado de la respuesta de Paxdiablo aquí: https://.com/a/4023921/2694511 ):

#include <stdio.h> #include <string.h> #include <stdlib.h> // Used for strtol #define OK 0 #define NO_INPUT 1 #define TOO_LONG 2 #define NaN 3 // Not a Number (NaN) int strIsInt(const char *ptrStr){ // Check if the string starts with a positive or negative sign if(*ptrStr == ''+'' || *ptrStr == ''-''){ // First character is a sign. Advance pointer position ptrStr++; } // Now make sure the string (or the character after a positive/negative sign) is not null if(*ptrStr == NULL){ return NaN; } while(*ptrStr != NULL){ // Check if the current character is a digit // isdigit() returns zero for non-digit characters if(isdigit( *ptrStr ) == 0){ // Not a digit return NaN; } // else, we''ll increment the pointer and check the next character ptrStr++; } // If we have made it this far, then we know that every character inside of the string is indeed a digit // As such, we can go ahead and return a success response here // (A success response, in this case, is any value other than NaN) return 0; } static int getLine (char *prmpt, char *buff, size_t sz) { int ch, extra; // Get line with buffer overrun protection. if (prmpt != NULL) { printf ("%s", prmpt); fflush (stdout); } if (fgets (buff, sz, stdin) == NULL) return NO_INPUT; // If it was too long, there''ll be no newline. In that case, we flush // to end of line so that excess doesn''t affect the next call. // (Per Chux suggestions in the comments, the "buff[0]" condition // has been added here.) if (buff[0] && buff[strlen(buff)-1] != ''/n'') { extra = 0; while (((ch = getchar()) != ''/n'') && (ch != EOF)) extra = 1; return (extra == 1) ? TOO_LONG : OK; } // Otherwise remove newline and give string back to caller. buff[strlen(buff)-1] = ''/0''; return OK; } void validate_input(int responseCode, char *prompt, char *buffer, size_t bufferSize){ while( responseCode != OK || strIsInt( buffer ) == NaN ) { printf("Invalid input./nPlease enter integers only!/n"); fflush(stdout); /* It might be unnecessary to flush here because we''ll flush STDOUT in the getLine function anyway, but it is good practice to flush STDOUT when printing important information. */ responseCode = getLine(prompt, buffer, bufferSize); // Read entire STDIN } // Finally, we know that the input is an integer } int main(int argc, char **argv){ char *prompt = "Please Insert X value/n"; int iResponseCode; char cInputBuffer[100]; int x, y=0; int *p = &x; while(y < 5){ iResponseCode = getLine(prompt, cInputBuffer, sizeof(cInputBuffer)); // Read entire STDIN buffer validate_input(iResponseCode, prompt, cInputBuffer, sizeof(cInputBuffer)); // Once validate_input finishes running, we should have a proper integer in our input buffer! // Now we''ll just convert it from a string to an integer, and store it in the P variable, as you // were doing in your question. sscanf(cInputBuffer, "%d", p); y++; } }

Solo como un descargo de responsabilidad / nota: hace mucho tiempo que no escribo en C, así que me disculpo por adelantado si hay algún error en este ejemplo. Tampoco tuve la oportunidad de compilar y probar este código antes de publicarlo porque estoy apurado en este momento.