Jump to content
waza

Limpar buffer do stdin

Recommended Posts

waza

Boas pessoal,

Bem, eu tenho usado sempre o rewind, pois o fflush não faz nada.

Faço bem em usar o rewind, ou será melhor adoptar outro método?

Obrigado ;)

Share this post


Link to post
Share on other sites
pmg

Não tens garantia de que o stream stdin seja "seekable". O rewind só pode ser usado em streams que são seekable. De acordo com a informação sobre fseek() do POSIX-1.2008 (agora não posso verificar o Standard do C) chamar fseek() (ou rewind()) com um stream que não é seekable, tem um comportamento definido pela implementação --- ou seja, não faz sempre a mesma coisa de compilador para compilador, de SO para SO, ...

A melhor maneira de lidar com dados vindos do utilizador é ler os dados com fgets() e depois tratá-los consoante as necessidades.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
HappyHippyHippo

solução portável:

while (getchar() != '\n') /* void */;

podos fazer uma macro para simplificar:

#define CLEAR_STDIN (while (getchar() != '\n') /* void */;)

// ...

scanf("%d", &i);
CLEAR_STDIN;


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
pmg

solução portável:

while (getchar() != '\n') /* void */;

O grande problema desta solução é o EOF ...

Edited by pmg

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
HappyHippyHippo

O grande problema desta solução é o EOF ...

sim , mas sempre é melhor que o rewind :D


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
pwseo

A solução do HappyHippyHippo tem outro problema, penso eu: se não existir nada no buffer, então a getchar() vai bloquear o programa até que haja novo input, não é? Para quem está a utilizar scanf() não tem problema porque habitualmente fica lá o '\n', mas para quem utilize fgets() e queira descartar um hipotético excesso de input penso que não dá.

Uma solução passaria por enfiar um caracter no stdin de forma a evitar o caso em que não há nada para ler e só depois correr o loop que limpa a stream:

void discard_input (void)
{
   int c;
   ungetc('a', stdin);
   while (c = getchar(), c != '\n' && c != EOF);
}

Que acham? (falta verificar erros da ungetc(), mas à partida funciona)

Share this post


Link to post
Share on other sites
HappyHippyHippo

Que acham? (falta verificar erros da ungetc(), mas à partida funciona)

parece uma boa solução, mas quem usa fgets não anda a limpar a entrada :D


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
pwseo

parece uma boa solução, mas quem usa fgets não anda a limpar a entrada :D

Sim, é verdade que tipicamente isso não acontece, mas imagina que alguém, por algum motivo estranho, excede o teu buffer de 1024 caracteres -- o excesso não é lido pela fgets(), ficando no stdin. Imagina então que de seguida o teu programa pergunta se o utilizador deseja rm -rf / e o primeiro caracter pendurado no stdin é 'y' :P

De qualquer modo, isto também pode ser contornado usando algo como ncurses ou semelhante para interactivamente limitar os dados introduzidos pelo utilizador, mas a função que fiz é mais simples que incluir uma lib inteira (e é portável).

Edited by pwseo

Share this post


Link to post
Share on other sites
pmg

Com o fgets() convem que te certifiques se o input foi completamente lido. Para isso verifica se o ultimo caracter foi um '\n'.

Se foi um '\n' leste o input todo.

Se nao foi um '\n' ou ha mais input ou chegaste a EOF 'prematuro'. Uma coisa simples de fazer (mas nao necessariamente correcta) é ignorar os caracteres extra

while (fgets(buffer, sizeof buffer, stdin)) {
   len = strlen(buffer); /* len nao pode ser 0 com stdin's de texto */
   if (buffer[len - 1] != '\n') {
       /* leitura incompleta ou EOF prematuro */
       if (feof(stdin)) {
           /* EOF prematuro */;
       } else {
           int ch;
           while ((ch = getchar()) != '\n' && ch != EOF) /* void */; /* ignora caracteres extra */
           if (ch == EOF) /* EOF prematuro */;
       }
   }
   /* buffer tem os primeiros caracters do input, pode nao ter '\n' */
}

  • Vote 1

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.