__KERNEL__
(usa Arch Linux)
Enviado em 22/10/2007 - 15:00h
Vocês não sabem que raiva eu tenho e alguns professores mal informados de faculdades porcausa disso... E dos cadas da Microsoft que escreveram uma libc em desconformidade com os padrões.
Se vocês lerem as man pages do fflush, verão que a função dele é sincronizar o buffer de um stream de escrita com o arquivo do disco, sem o fechamento do file-descriptor do arquivo(ou seja, chamar realmente o write()).
No nosso amigo que segue pra caramba os padrões(Windows), o fflush meche também em buffers de streams de leitura. Ele simplesmente pula a linha caso o stream esteja no fim dela.
Exemplificando... Você tem o seguinte arquivo como stdin(sim, isso pode ser o que você digita):
|123 234\n
hahaha haq ha au ha uah uah\n
123 123\n
Considere o | como sendo a posição de leitura do stream. Quando você der um scanf("%d",ponteiroDeInt), ele vai ficar assim:
123| 234\n
hahaha haq ha au ha uah uah\n
123 123\n
Repetindo o processo do scanf com %d, ele ficará assim:
123 234|\n
hahaha haq ha au ha uah uah\n
123 123\n
Caso você desse um fgets ou um gets(pura ignorancia), ele vai pegar a linha atual(da posição de leitura, ilustrada por | nestr exemplo) até o seu fim(\n, incluindo o mesmo).
Ou seja, o resultado será um \n.
Agora vamos esquecer o fgets ou o gets acima, pois eles não foram executados ainda. Em bibliotecas padrão que tem conformidade com o C89 e o C99, o fflush nem tem porque ser usado no stdin, pois ele é um buffer de leitura apenas. Já no nosso amigo windows, que não respeita padrões, ele faz o seguinte com teu buffer de leitura:
123 234\n
|hahaha haq ha au ha uah uah\n
123 123\n
Por isso, se você der um fgets após um scanf/fflush(stdin) no windows, você vai ter o resultado desejado, no windows não.
Graças a esta porcaria do windows, eu perdi algumas noites de sono.
Resumindo: Não digam besteiras do tipo "fflush limpa o buffer do teclado". Nem na porcaria do windows ele faz isso, pois se você fizer o teste colocando um scanf, depois um fflush e depois outro scanf, e na entrada digitar "234 234", você vai ver que ele não vai parar pra te perguntar o segundo numero.
Mas graças a essa porcaria que se criou essa cultura de usar fflushs de maneira louca por aí, pois os professores burros leram que tem que usar fflush em algum livro de algum winuser retardado, e repetem pros alunos sempre sem sequer explicar as razões.
Agora, sobre a pergunta do amigo que perguntou sobre limpar o buffer do teclado... Bom, isso é algo bem relativo. Se você quer que a entrada tenha um valor por linha, usando o scanf, você PODE(e não deve, pois existem outras alternativas) fazer essa limpeza de buffer mesmo. Para fazer isso, em Linux com glibc você usa __fpurge, em BSD fpurge, e em outros sistemas você FICA NA MÃO PORQUE ISSO NÃO É PADRÃO.
Existem "workarounds" para contornar esta situação. Nunca pesquisei para saber se há um método melhor, talvez haja, se souberem me digam...
Exemplo(supondo que c seja um array de 50 chars a ser lido, e a seja um inteiro, e a entrada sera algo como "250\nhahaha hehehe hohoho\n"):
scanf("%d\n",&a);
fgets(c,50,stdin);
/** Aqui você terá problemas de compatibilidade com RWindows e Mac, porcausa do line separator deles que não é um simples \n*/
------------------ ou -----------------
scanf("%d",&a);
fgets(c,50,stdin);
fgets(c,50,stdin);
/** Aqui a coisa ta mais feia, mas este é realmente pra funcionar em todos os sistemas */
A idéia do amigo que falou de dar um getchar() é interessante, porém se o cara colocar um espaço depois do número(lembre-se, usuário faz tudo), já "
[*****]" o programa.
Um método que também já usei, é criar uma função void pulaLinha();
Ex:
void pulaLinha(){
while(getchar()!='\n');
}
Mas eu particularmente prefiro não usar, considero uma gambiarra tremenda, hehehe... Mas lembre-se que é mais "garantido" que o fgets, pois não para se receber um NULL(contrabarra(\) zero(0))
Acho que isso é tudo pessoal, foi bom escrever pra mim desabafar... Já perdi uma noite porcausa dum código que tinha isso(fflush(stdin)), e funcionava no Windows e no Linux não... E eu estava pensando que o gets/fgets fossem as "chamadas despadronizadas" da libc do Windows.