sábado, 9 de julho de 2016

9.0 - Buffer e as funções fflush e __fpurge

Buffer: "Uma região de memória temporária utilizada para escrita e leitura de dados."



O problema de usar scanf, getchar, getc e fgetc para receber caracteres em C


"Ora, é só declarar duas variáveis char e usar a scanf duas vezes, uma para cada variável", é que você deve ter pensado para criar o tal programa.

Vamos fazer isso então, e ver o resultado:

#include <stdio.h>

int main()
{
    char letra1, letra2;

    printf("Insira um caractere: ");
    scanf("%c",&letra1);

    printf("Insira outro caractere: ");
    scanf("%c",&letra2);

    printf("Você digitou: '%c' e '%c'", letra1, letra2);
}


Eu digitei 'C' (a melhor letra do alfabeto), dei enter, e antes de digitar a próxima letra o progarma terminou, exibindo a seguinte mensagem:
"Você digitou: 'C' e '
'"

Nossa! Estranho, não? Será que hackeamos a linguagem C e descobrimos uma falha?
Não ;)

Note que digitei 'C' e enter...mas enter também é uma tecla, e é representada por '\n', lembra?
Ou seja, o C entendeu que nossa segunda letra era o enter!

A solução para isso é bem simples.
Na função scanf, dê um espaço entre a aspa " e o símbolo %c.
Nosso código fica assim:

#include <stdio.h>

int main()
{
    char letra1, letra2;

    printf("Insira um caractere: ");
    scanf("%c",&letra1);

    printf("Insira outro caractere: ");
    scanf(" %c",&letra2);

    printf("Você digitou: '%c' e '%c'", letra1, letra2);
}




Pronto! Agora funciona perfeitamente!
Pois esse simples espaço é um comando para o C desconsiderar o enter, tab ou espaço em branco.
Sim, precisa nem dar enter. Tente aí digitar uma letra, dar espaço (ou tab) e a outra.

Ok, mas só é possível fazer isso na scanf().
E na getchar(), getc() e fgetc()?

Limpando o buffer em C: fflush e __fpurge

Ainda no primeiro exemplo desse artigo ( o que dá problema ), digitamos a letra 'C', que é armazenada na variável 'letra1' e em seguida apertamos enter.

Esse caractere (enter), ficará armazenado no buffer do teclado (um memória temporária).

Em seguida, noss programa em C pede para que algo seja armazenado na variável 'letra2'.
Porém, antes do C receber um novo dado do usuário, ele checa se não tem mais alguma coisa armazenada no teclado (ele sempre faz isso...fez antes, para pegar a letra 'C'). E lá tem um caractere sim, o enter.

Então o programa pega esse caractere e o coloca na variável letra2, e é por isso que aparece uma quebra de linha em nosso programa.

Portanto, uma alternativa, caso não queria usar o espaço entre " e o %c na scanf, é limpar o buffer após cada scanf(), getchar(), getc() ou fgetc().

Para limpar o buffer em Windows, use: fflush(stdin)
Para limpar o buffer em Linux, use: __fpurge(stdin)

Veja como fica nosso programa original, funcionando do jeito que queríamos:


#include <stdio.h>

int main()
{
    char letra1, letra2;

    printf("Insira um caractere: ");
    scanf("%c", &letra1);

    fflush(stdin);
    __fpurge(stdin);

    printf("Insira outro caractere: ");
    scanf("%c", &letra2);

    printf("Você digitou: '%c' e '%c'", letra1, letra2);
}



Fica ao seu dispor escolher como vai ser.
E se habitue com essas coisas, em C há várias maneiras de se fazer várias coisas. Muitas vezes, porém, a solução que usamos não é muito segura ou portável, mas é a mais simples.

Limpar o buffer, por exemplo, nem sempre é algo desejável, e para programação mais profissional e segura não é recomendado que se use fflush por exemplo.

Mas para quem está  começando, não há problema algum ficar limpando o buffer após cada scanf, e o  scanf (embora seja arriscado e não indicado em alguns casos) é o mais usado.
Até a próxima

Nenhum comentário:

Postar um comentário