paulo1205
(usa Ubuntu)
Enviado em 26/05/2015 - 13:26h
Thihup escreveu:
Não se utiliza o fflush, pois isso é apenas para buffers de saida, se esse código funciona, é, só pode ser bug do windows;
Calma, Thiago.
O padrão não diz que não se pode usar
fflush() em um stream de entrada. Na verdade, o padrão não diz absolutamente nada sobre streams de entrada com
fflush(), limitando-se a descrever o comportamento da função quando ela é aplicada em streams de saída.
Assim sendo, a implementação comum no mundo Microsoft, de usar
fflush() para descartar dados quando aplicada em streams de entrada, não viola o padrão, nem se pode dizer que é um bug; ela é uma extensão, e bem documentada, do padrão, numa área em que ele se omite de definir o que deveria acontecer.
O problema é que essa extensão não pode ser tomada como universal. Uma implementação como a dos BSDs (e que já foi também a da glibc do Linux, só que ela passou a funcionar como no Windows de alguns anos para cá), que ignoram a aplicação de
fflush() sobre stream de entrada, também é uma implementação válida, pois atende ao que o padrão efetivamente determina, e só.
O problema, em suma, não é usar a extensão, mas sim:
1) compartilhar publicamente (como aqui neste fórum) código que depende do comportamento estendido, pois vai limitar a capacidade de usar o código compartilhado sem a necessidade de modificá-lo;
2) viciar-se em usar código não padronizado;
3) deixar de aprender formas mais adequadas de fazer, que não são tão trabalhosas e que podem funcionar em qualquer máquina;
4) viciar-se em não tomar o devido cuidado com o tratamento do que é recebido na entrada, confiando que desprezar o inesperado (ou esperar algo que possa ser ignorado) seja uma solução sempre suficiente; mais cedo ou mais tarde, encontra-se um padrão de entrada tal que a solução mais fácil acarreta perda de dados ou provoca a execução de código imprevisto, e isso é muito chato de identificar e corrigir.
Troque por um getchar() ou um espaço antes do scanf: scanf(" %[^\n]s")
Dois problemas:
1)
getchar() não é equivalente ao
fflush(stdin) do Windows. Ele pode resolver alguns casos, mas é pior em outros. Por exemplo, se alguém chamar
fflush(stdin) do Windows depois de um
fgets(), nada vai acontecer, pois o buffer já estará vazio; se fosse um
getchar(), o programa necessariamente pararia para ler um caráter a mais. Por outro lado,
getchar() só engole um caráter, ao passo que
fflush(stdin) do Windows despreza todo o buffer de entrada. Isso implique que se, por exemplo, o programa usa
scanf("%d", &n); fflush(stdin); e, durante a execução desse trecho, o usuário do programa digita “
1, 2, 3, testando!\n”, o programa vai ler o 1 e gravá-lo em
n, e vai desprezar o resto da linha.
2) Como eu já disse noutro tópico,
scanf(" %[^\n]s", buf) tem erro na formatação. Mais de um, aliás. O mais gritante é que o caráter ‘
s’ não faz parte da conversão iniciada por “
%[” e encerrada pelo “
]”; na posição em que ele está, ele é usado apenas como um marcador na entrada (isto é: um caráter que tem de estar presente para a execução de
scanf() continuar comparando a entrada com string de formatação; se não estiver, a função é interrompida imediatamente, e o caráter que da entrada que não bateu com o marcador é colocado de volta no buffer de entrada). Outro problema é que o espaço antes da conversão “%[” vai impedir a entrada de uma linha vazia, caso o usuário queira, por exemplo, deixar a senha em branco. O terceiro erro é que mesmo com essa aparente sofisticação, você acaba deixando a quebra de linha no buffer de entrada após a leitura.
Não se utiliza o gets, troque por scanf("%[^\n]s"), assim, terá o mesmo efeito.
Mesmos erros: o ‘
s’ está sobrando (a rigor, ele faz com que
scanf() aborte a execução antes de chegar ao fim da strings de formatação) e a leitura deixa o '\n' no buffer, o que é bem diferente de
gets(), que o consome. Provavelmente você quis dizer
scanf("%[^\n]%*1[\n]", buf).
No entanto, quando você troca
gets(buf) por
scanf("%[^\n]%*1[\n]", buf), acaba trocando seis por meia dúzia. O principal problema com
gets() é que ele não leva em consideração o tamanho de
buf na hora de copiar os caracteres que vão chegando pela entrada, e pode acabar ultrapassando esse tamanho se a linha for longa demais, corrompendo a memória ao escrever além do fim do buffer. A mesmíssima coisa acontece com
scanf() se você não impuser um limite.
Para efetivamente corrigir o problema de
gets() através
scanf(), você deve colocar um limite de caracteres na conversão com “
%[”. Por exemplo, se
buf tiver tamanho 20, você deveria usar
scanf("%19[^\n]%*1[\n]", buf).
Seja "travesso" e utilize algo assim para evitar linhas desnecessárias:
[exemplo suprimido]
Acho que não é necessário “roubar”. Creio que dá para fazer com 15 linhas mesmo sem aglutinar excessivamente o código. Se aglutinar na marra fosse a solução, o professor poderia ter pedido para fazer o programa inteiro numa linha só.