Salem Ribeiro Posted April 3, 2020 at 01:38 AM Share Posted April 3, 2020 at 01:38 AM Alguém consegue me explicar de maneira clara pq meu programa passa reto pela função fgets? #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <ctype.h> /*----------------------------------------------------------------------------*/ /* Data Structs */ /*----------------------------------------------------------------------------*/ struct DataNode { int id; char *name; struct DataNode *node; }; struct DataMove { struct DataNode *previous; struct DataNode *next; }; struct HeadNode { int count; struct DataNode *first_node; }; /*----------------------------------------------------------------------------*/ /* Functions */ /*----------------------------------------------------------------------------*/ struct DataNode *create_list() { struct DataNode *node; node = (struct DataNode*)malloc(sizeof(struct DataNode)); if (node) return(node); else return(NULL); } struct DataNode *add(int i, char *name, struct DataNode *item) { item->id = i; item->name = name; item->node = create_list(); if (item->node) return (item->node); else return (NULL); } /* MAIN */ /*----------------------------------------------------------------------------*/ int main(void) { struct HeadNode head; struct DataMove node; char value_menu; char name[50]; head.count = 0; head.first_node = create_list(); node.next = head.first_node; if (head.first_node) { value_menu = '0'; do{ printf("\e[H\e[2J"); printf("ESTUDO DE LISTAS ENCADEADAS\n"); printf("1)\tAdicionar\n"); printf("2)\tProcurar\n"); printf("3)\tListar\n"); printf("4)\tOrdenar\n"); printf("5)\tExcluir\n"); printf("0)\tSair\n"); printf("MENU: "); scanf("%c", &value_menu); switch (value_menu) { case '1': printf("\nDigite o nome: "); fgets(name, 50, stdin); head.count ++; node.previous = node.next; node.next = add(head.count, name, node.next); printf("\n\nCadastro realizado com sucesso!!!"); break; } }while (value_menu != '0'); } else { printf("Não foi possível criar lista"); return (1); } return(0); } Debugando percebi que fgets acaba recebendo um \n e não sei como resolver esse problema ridículo estudo_list.c Link to comment Share on other sites More sharing options...
Salem Ribeiro Posted April 3, 2020 at 01:43 AM Author Share Posted April 3, 2020 at 01:43 AM Existe um anexo caso queira testar. Minha maquina roda o elementary e estou complilando com gcc Link to comment Share on other sites More sharing options...
Marioh Posted April 3, 2020 at 02:30 AM Share Posted April 3, 2020 at 02:30 AM Se eu nao me engano tu tem que esvaziar os stdin. tenta: char clear; while((clear = getchar()) != '\n' && clear != EOF); depois do seu primeiro scan. espero que ajude. Link to comment Share on other sites More sharing options...
Salem Ribeiro Posted April 3, 2020 at 02:47 AM Author Share Posted April 3, 2020 at 02:47 AM Obrigado mario Eu encontrei essa solução nas internet. Mas é difícil acreditar que isso seja a melhor forma de resolver isso. De qualquer forma muito obrigado por responder. Link to comment Share on other sites More sharing options...
Administrators Fernando Mercês Posted April 3, 2020 at 03:46 AM Administrators Share Posted April 3, 2020 at 03:46 AM Yep, como o @Marioh falou, é preciso consumir o buffer (no caso, o stdin, que é o buffer que você tá usando). Acontece que ao digitar 1 e pressionar [enter], você insere dois bytes no buffer: o '1' e '\n'. Aí você tá consumindo só o primeiro com o seu scanf(), deixando o '\n' lá. Como a fgets() lê até encontrar um \n, ela o encontra logo de cara não copia mais nada pra char nome[]. Ou seja, o comportamento é o esperado. Tem outras soluções além da do Marioh. No final vão meio que dar no mesmo: 1. Usando a fflush(): scanf("%c", &value_menu); fflush(stdin); 2. Lendo o \n (que é o segundo byte) pra outra variável (meio feio): char tmp; scanf("%c%c", &value_menu, &tmp); No caso acima você não usaria o char tmp nunca mais, mas se olhar a documentação da scanf, vai ver que tem isso ó: CONVERSIONS Following the % character introducing a conversion, there may be a number of flag characters, as follows: * Suppresses assignment. The conversion that follows occurs as usual, but no pointer is used; the result of the conversion is simply discarded. 3. Ou seja, podes usar o *: scanf("%c%*c", &value_menu); Assim não vai precisar da variável auxiliar. Independente do que escolher (e provavelmente há soluções além dessas), o importante é você entender o que se passa. ? Abraço! Link to comment Share on other sites More sharing options...
Marioh Posted April 3, 2020 at 05:01 AM Share Posted April 3, 2020 at 05:01 AM Aí @Fernando Mercês, posso tá errado mas fflush não tem comportamento definido quando usado no stdin, tem ? Link to comment Share on other sites More sharing options...
Administrators Fernando Mercês Posted April 3, 2020 at 10:26 AM Administrators Share Posted April 3, 2020 at 10:26 AM Eita, não sabia disso. Você tem razão: a função é preparada para limpar buffers de saída, não de entrada. Tenho a sensação de já ter usado com buffer de entrada, então deve ter bastante código bugado meu por aí! kkkk Existe a fpurge também, mas não sei se é padrão. Nunca usei. Obrigado por alertar, @Marioh! ? Abraço! Link to comment Share on other sites More sharing options...
Administrators Fernando Mercês Posted April 3, 2020 at 12:42 PM Administrators Share Posted April 3, 2020 at 12:42 PM @fredericopissarra, pode dar uma luz aqui? ? Link to comment Share on other sites More sharing options...
Salem Ribeiro Posted April 3, 2020 at 12:47 PM Author Share Posted April 3, 2020 at 12:47 PM Bom dia pessoal Eu fiz oq o grande @Mariohrecomendou e o problema foi solucionado, já tinha percebido via lldb a questão do '\n' sendo consumido pela variável name e imaginei que uma outra função resolvesse esse problema. Tentei o getchar, getc, getch e fflush e só apanhei. Vou estudar melhor essa questão do stdin, voltarei aqui se consegui avançar e encontrar algo mais clean. Muito obrigado @Marioh @Fernando Mercês 10 horas atrás, Marioh disse: Se eu nao me engano tu tem que esvaziar os stdin. tenta: char clear; while((clear = getchar()) != '\n' && clear != EOF); depois do seu primeiro scan espero que ajude. Link to comment Share on other sites More sharing options...
Marioh Posted April 3, 2020 at 06:22 PM Share Posted April 3, 2020 at 06:22 PM @Fernando Mercês Parece que o fflush pode funcionar dessa maneira só não é garantido, li em algum lugar que os kernels atuais suportam, mas não sei ao certo tô com o 5.5.13 e comigo não funciona. Já o __fpurge da stdio_ext.h funciona examento como esperado. Li também em algum lugar (acho que foi no reddit) que realmente nao faz sentido dar um "flush" no stdin, afinal pra onde ele vai ser flushado ? Lá na manpage do fflush ele fala que se a stream for de output ele força um write nos dados em buffer que ultimamente tem um destino. Link to comment Share on other sites More sharing options...
fredericopissarra Posted April 3, 2020 at 06:26 PM Share Posted April 3, 2020 at 06:26 PM Sorry... só vi agora. Fiquei internado num hospital na última semana (não... não foi o coronga!)... O detalhe é que scanf varre um stream em busca do formato desejado, mas deixa para trás o restante, uma vez atendido o formato. Ao usar "%c" você pede a conversão de um único caractere, todos os demais que o seguem, "ficam para trás"... Acontece que stdin normalmente precisa de um '\n', quando o redirecionamento é feito para o teclado e '\n' é o final de linha interpretado pelo fgets() também... Não... usar fflush com streams de entrada não resolve, uma vez que, como @Marioh apontou corretamente, isso é undefined behavior. De fato, o comportamento, em alguns OSs, é simplesmente ignorar a ordem de "despejo". Você pode tentar um scanf() diferente: scanf("%c ", &value_menu); Note o espaço depois do "%c". Isso faz com que quaisquer caracteres "separadores" sejam varridos, mas ignorados. Link to comment Share on other sites More sharing options...
fredericopissarra Posted April 3, 2020 at 11:01 PM Share Posted April 3, 2020 at 11:01 PM Exemplo: #include <stdio.h> #include <string.h> int main( void ) { char v, *p; char buffer[16]; // Lê 1 char de stdin, mas ignora todos os "separadores" (isspace()) subsequentes... scanf( "%c ", &v ); // Lê 16 chars à partir do primeiro caracter válido do stream stdin. fgets( buffer, sizeof buffer, stdin ); // Livra-se do '\n' no final da string, se houver. if ( p = strchr( buffer, '\n' ) ) *p = '\0'; printf( "'%c' : \"%s\"\n", v, buffer ); } Testando: Ahhhhhhhhhh... NÃO use gets()... é uma função obsoleta! Link to comment Share on other sites More sharing options...
brenoacf Posted April 6, 2020 at 05:20 PM Share Posted April 6, 2020 at 05:20 PM Legal pessoal! Eu sempre utilizei a função scanf com um espaço à mais no final, quando queria ler apenas um caractere. Não sei onde aprendi dessa forma, mas a questão é que nunca passou pela minha cabeça o motivo de fazer isso. A explicação foi nota 10! Obrigado! Abraços. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.