segunda-feira, 25 de fevereiro de 2008

O scanf engana

Quando falei sobre a função scanf, chamei a atenção para a limpeza do buffer do teclado.
Naquele momento enfatizei que limpar o buffer do teclado evitaria algumas dores de cabeça.
Execute o código abaixo e verifique o seu funcionamento.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char chr1, chr2;
007:    
008:    printf("Digite o primeiro caractere: ");
009:    scanf("%c", &chr1
010:    printf("Digite o segundo caractere: ");
011:    scanf("%c", &chr2);
012:    printf("Primeiro caractere %c\nSegundo caractere: %c\n", chr1, chr2);
013:    system("PAUSE");
014:    return 0;
015:  }


Não fique nervoso tentando digitar o segundo caractere. Esse problema é bastante comum nos códigos de programadores pouco experientes. Tente limpar o buffer do teclado, utilizando a instrução fflush(stdin) antes de cada scanf. Você verá que agora o segundo caractere é lido.
Por que isso ocorre? Imagine o buffer do teclado como um arquivo seqüencial, onde o scanf retira os dados.
Para o exemplo anterior, na linha 9, o scanf espera que você digite um byte (estamos lendo variáveis do tipo char). O que você faz? Digita o caractere e em seguida o enter. Supondo que você digitou o caractere V, o buffer do teclado fica:


V\n


O \n representa o enter.
Após a execução da linha 9, o caractere V é armazenado na variável chr1, deixando o \n no buffer do teclado. Adivinhe que receberá o \n? Correto, a variável chr2. Por esse motivo ela não é lida!
Quando você usa a instrução fflush(stdin), e limpa o buffer do teclado, o \n sai do buffer, deixando ele limpo para a próxima leitura.

4 comentários:

Golden ball futebol clube disse...

Guiera,

Após feita uma vez o fflush,ele precisa ser feito a cada leitura? ou quando faço no inicio do programa ele já deixa limpo para todas as entradas?

Att,

Daniel

Anderson Guiera disse...

Daniel,

Ele deve ser feito a cada leitura.
Você pode testar o programa exemplo deste post e colocar apenas um fflush(stdin), no início do programa, e verá que o problema persiste.
Para esse teste eu usei o Dev C++.

Sds

Guiera

Anônimo disse...

Aparentemente este comando só funciona no windows.

eudson disse...

Isso é má pratica de programação, não se esqueçam.O fflush(), foi originalmente desenvolvido para limpar buffer de saída e nao de entrada.O ideal seria usar os recursos que a função scanf nos fornece ou até mesmo utilizar um getchar () (que tambem é má pratica de programaçao) ou uma outra funçao para leitura de dados como a fgets().
Como ja foi dito anteriormente o uso do fgets () em outras plataformas, como a GNU-linux, não funciona.Logo pensar em desenvolver softwares portaveis utlizando a fgets () dessa maneira pode resultar em futuras dores de cabeça.