LLuciano Postado Agosto 20, 2023 em 17:16 Compartilhar Postado Agosto 20, 2023 em 17:16 Olá pessoal! Estou estudando C sozinho. Em vários exercícios tem a necessidade de criar uma espécie de menu com opções. Mas, considerando o que eu aprendi até agora, é muito fácil de dar um erro caso o usuário digite algo errado, como por exemplo uma letra quando eu esperava um inteiro. Isso me dá uma angustia, ficar fazendo exercício cujo o programa pode ser facilmente quebrado. Eu procurei uma função na biblioteca padrão para isso mas não encontrei, então tentei fazer eu mesmo uma solução. Eis as dúvidas: 1 - Existe alguma função que já implementa isso? 2 - O código que desenvolvi está funcionando... mas parece que estou com a mente viciada.Fico com a impressão de que poderia ser mais simples mas não consigo fazer melhor. Alguém tem alguma sugestão? (Fiz somente considerando opções numéricas, não alfabéticas, ou com palavras) Eis o código: #include <stdio.h> #include <ctype.h> int menuNumberCheck (void); int main(void){ int choice = 0; do { printf("%s", "Digite um número de 0 a 10 ou digite 11 para finalizar: "); choice = menuNumberCheck(); if (choice < 0 || choice > 11){ puts("Opção inválida"); } else printf("Você escolheu a opção %d\n", choice); } while (choice != 11); puts("Programa finalizado"); return 0; } int menuNumberCheck (void){ int check = 1; char c; int number = 0; int loopcount = 0; while ((c = getchar()) != '\n'){ if (isdigit(c) && check == 1){ //check multpiplication overflow: //se verdadeiro é que vai ocorrer overflow e retornar erro. //multiplica o dígito pode 10 para encontrar a posição (unidade, dezena e etc); if (__builtin_smul_overflow(number, 10, &number)) { puts("Overflow"); check = 0; //check sum overflow //soma o digito encontrado na unidade //se verdadeido é que vai ocorrer overflow e retornar erro. // c-48 para encontrar o número na tabela ANSCI-I } else if (__builtin_sadd_overflow(number, c-48, &number)) { puts("Overflow"); check = 0; } else loopcount++; } else check = 0;//falso se encontrar algum caracter não numérico. } if (check == 0 || loopcount == 0){ return -1; } else return number; } 1 Citar Link para o comentário Compartilhar em outros sites More sharing options...
mauro_b Postado Agosto 23, 2023 em 22:29 Compartilhar Postado Agosto 23, 2023 em 22:29 Olá, @LLucianoexperimente uso com a função scanf da biblioteca padrão, após leitura de sua definição reescreva teu código. Um exemplo C'11 #include <stdio.h> int main() { int choice = -1; do { printf("%s", "Digite um número de 0 a 10 ou digite 11 para finalizar: "); int decimal_input = scanf("%d", &choice); if (choice < 0 || choice > 11){ puts("Opção inválida"); if (decimal_input == NULL) scanf("%*s"); /*se entra com caractere não decimal, consuma sua string*/ } else printf("Você escolheu a opção %d\n", choice); } while (choice != 11); puts("Programa finalizado"); return 0; } 1 1 Citar Link para o comentário Compartilhar em outros sites More sharing options...
LLuciano Postado Agosto 24, 2023 em 17:22 Autor Compartilhar Postado Agosto 24, 2023 em 17:22 (editado) Em 23/08/2023 em 19:29, mauro_b disse: Olá, @LLucianoexperimente uso com a função scanf da biblioteca padrão, após leitura de sua definição reescreva teu código. Um exemplo C'11 #include <stdio.h> int main() { int choice = -1; do { printf("%s", "Digite um número de 0 a 10 ou digite 11 para finalizar: "); int decimal_input = scanf("%d", &choice); if (choice < 0 || choice > 11){ puts("Opção inválida"); if (decimal_input == NULL) scanf("%*s"); /*se entra com caractere não decimal, consuma sua string*/ } else printf("Você escolheu a opção %d\n", choice); } while (choice != 11); puts("Programa finalizado"); return 0; } Nossa! Valeu! Era só ter estudado o scanf decentemente! Tinha que ser mais simples que eu estava fazendo. Editado Agosto 24, 2023 em 19:11 por LLuciano Só agora consegui compilar o código. 2 Citar Link para o comentário Compartilhar em outros sites More sharing options...
Devair Postado Maio 31, 2024 em 16:50 Compartilhar Postado Maio 31, 2024 em 16:50 essa questão de ler o teclado é bem complicado mesmo e muitas tentativas de implementar funções que resolvam já existem pela internet , e resolvem a maioria dos casos , e todas as tentativas são válidas , porém algumas vezes surge algum erro , e uma solução que encontrei em alguns sites foi essa , que usa uma string da linguagem C , para pegar o que for digitado pelo usuário , pois em uma "string" pode se inserir qualquer caractere , e assim não haverá erro na leitura , e não vai quebrar o código , e depois de pegar os dados usar a função "atoi" da da biblioteca "<stdlib.h>" da linguagem C para converter a string em um valor decimal normal , e assim se houver caracteres inválidos no início , o valor retornado será zero mesmo , e se o início for um valor válido esse valor é que será retornado , e que sempre será maior ou igual a zero , e funcionou bem , . . . #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int choice = -1;/// escolha char str[20] = ""; char c = 'w'; do { printf("%s", "Digite um número de 0 a 10 ou digite 11 para finalizar: "); scanf("%s", str); choice = atoi( str ); printf("val Choice = %d\n",choice); if ( /*choice < 0 || */ choice > 11)/// nunca serAh menor Q zero { while(c != '\n' && c != EOF)/// limpar o buffer c = fgetc(stdin); puts("Opção inválida"); } else printf("Você escolheu a opção %d\n", choice); } while (choice != 11); puts("Programa finalizado"); return 0; } Citar Link para o comentário Compartilhar em outros sites More sharing options...
fredericopissarra Postado Junho 3, 2024 em 16:33 Compartilhar Postado Junho 3, 2024 em 16:33 (editado) Well... UMA opção é usar o scanf(), como o povo te disse, mas há um detalhe: A função usa o stream stdin e os buffers de streams de entrada não podem ser "descartados" com fflush(). A função scanf() "varre" (scans) o stream em busca do formato informado. Uma vez que o formato foi completado, os dados são colocados nos ponteiros informados e o restante do buffer é mantido no stream. Por exemplo, isso pode ser problemático: int op; do { scanf( "%c", &op ); } while ( op != '0' ); O loop acima será executado DUAS vezes se op for igual a zero na primeira "varrida"... Ele será o valor digitado na primeira vez e '\n' na segunda (porque scanf deixará o '\n' no buffer do stream ao converter o caracter inicial. OBS: O formato %c exige um ponteiro para int, não para char! Geralmente o pessoal contorna isso adicionando um espaço no início do formato: scanf( " %c", &op ). Isso porque scanf() usa a função isspace() para ignorar "espaços", nesse caso. OUTRA solução mais "esperta" é usar a função fgets(), com um buffer de tamanho máximo conhecido: char buffer[11]; // 11 chars suporta valores de 9 algarismos + 1 '\n' e mais o '\0' final. char *p ... fgets( buffer, sizeof buffer, stdin ); buffer[sizeof buffer - 1] = '\0'; // para ter certeza que sempre tenhamos uma string. p = buffer + strspn( buffer, " \t\n\r" ); // ignora espaços, tabs, '\n' ou '\r' inciais, se houverem. op = atoi( p ); // lembrando que op será zero se a string não puder ser convertida. Com isso você garante que o buffer estará sempre vazio na próxima leitura (desde que buffer seja grande o suficiente para caber toda a "linha" lida) - omiti o teste do retorno de fgets() ai em cima por simplicidade - é bom testar se ele retorna ou não NULL. atoi() pode ser substituída por strtol() para maior controle de erros. Editado Junho 3, 2024 em 16:35 por fredericopissarra 1 1 Citar Link para o comentário Compartilhar em outros sites More sharing options...
LLuciano Postado Julho 3, 2024 em 13:51 Autor Compartilhar Postado Julho 3, 2024 em 13:51 Olha só que legal essa função que achei no livro C Primer Plus, funcionou muito bem. O único "erro" que achei é quando o usuário digita um número válido seguido de espaço e outra coisa (se for outro número o loop conta como várias escolhas). long get_long(void) { long input; char ch; while (scanf("%ld", &input) != 1) { while ((ch = getchar()) != '\n') putchar(ch); // dispose of bad input printf(" is not an integer.\nPlease enter an "); printf("integer value, such as 25, -178, or 3: "); } return input; } 1 Citar Link para o comentário Compartilhar em outros sites More sharing options...
fredericopissarra Postado Julho 3, 2024 em 14:34 Compartilhar Postado Julho 3, 2024 em 14:34 Um jeito mais fácil que ainda tem um problema: #include <stdio.h> int main( void ) { char buffer[128]; // um tamanho grande, arbitrário. puts( "Digite alguns números e <enter>" ); while ( fgets( buffer, sizeof buffer, stdin ) ) { // Atenção: `long int`, no Windows, é o mesmo que `int`. long long int n; if ( sscanf( buffer, " %lld", &n ) != 1 ) break; printf( "read: %lld\n", n ); } } Uma versão melhor: #include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char buffer[128]; // um tamanho grande, arbitrário. puts( "Digite alguns números e <enter>" ); while ( fgets( buffer, sizeof buffer, stdin ) ) { // Atenção: `long int`, no Windows, é o mesmo que `int`. long long int n; char *p; p = buffer + strspn( buffer, " \f\n\r\t\v" ); errno = 0; n = strtoll( p, NULL, 10 ); if ( errno ) { fputs( "ERRO convertendo string.\n", stderr ); continue; } printf( "read: %lld\n", n ); } } []s Fred 1 Citar Link para o comentário Compartilhar em outros sites More sharing options...
mauro_b Postado Agosto 7, 2024 em 16:02 Compartilhar Postado Agosto 7, 2024 em 16:02 (editado) Bom dia, @LLuciano ISSO É ERRO DO USUÁRIO E FALHA DO PROGRMADOR while|scanf|printf Interessante, porque este único “erro” é também uma falha do programador: falha o usuário por não entender a mensagem ou por não entender o programa; considere a má formatação dum campo uma limitação do programa, onde posso informar texto num campo numérico e com isso falhar. Essa falha configurará uma falha do progrmador, somente se não for tratada. Em tese, trata-se de falhas a partir das especificações e recursos da linguagem. Neste caso, imagine ser um exercício, e seu o apontamento alencou o estudo de 2 funções (scanf e printf) e uma declaração de repetição (while), com esses recursos não é possível limitar as teclas, aquilo que o usuário consegue teclar ou entrar numa linha, essas funções não têm poder para essas coisas. Logo, ele (o usuário) é livre para teclar texto num campo numérico, incluindo espaço. Para tratar essa falha ou impedir um erro, defina o terminador de campo, alerta para falhas, bem como valor padrão ou, até mesmo, o caso de solicitar que entre novamente com a linha válida. Sugere um exercício de estrutura de repetição comumente nomeado de VALIDAÇÂO DE CAMPO. Editado Agosto 7, 2024 em 16:02 por mauro_b 2 Citar Link para o comentário Compartilhar em outros sites More sharing options...
LLuciano Postado Outubro 3, 2024 em 14:09 Autor Compartilhar Postado Outubro 3, 2024 em 14:09 Olha só que legal que descobri esses dias, uma forma de limpar o buffer com o scanf... É muito sagaz o uso de Regex no scanf (e família).. dá pra fazer muita coisa legal. long int get_l_int(char *mensage) { char c[64] = {0}; long int n = 0; printf("%s", mensage); scanf("%64s", c); scanf("%*[^\n]"); //limpa o buffer. n = strtol(c, NULL, 0); return n; } Citar Link para o comentário Compartilhar em outros sites More sharing options...
Posts Recomendados
Participe da conversa
Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.