PROBLEMAS COM O COMANDO while(!feof(a)){

1. PROBLEMAS COM O COMANDO while(!feof(a)){

LINER DE SOUZA SANTOS
linersantos

(usa Ubuntu)

Enviado em 18/11/2020 - 10:26h

Bom dia a todos os internautas.
Preciso escrever um codigo que leia uma lista de numeros de um arquivo. Só que ao usar o comando
while(!feof(a)) 

o código lê a ultima linha duas vezes e o resultado final do calculo que estou fazendo sai errado por isso. Tem como resolver esse problema de fazer com que o comando acima nao leia a ultima linha duas vezes?


  


2. Re: PROBLEMAS COM O COMANDO while(!feof(a)){

Samuel Leonardo
SamL

(usa XUbuntu)

Enviado em 18/11/2020 - 23:38h

Eu diria que é preciso verificar logo depois de você ler a linha, não só na lógica do while:
Exemploe:

while (1) {
char line[256];
//lê uma linha
fgets(line, 256, file);
//agora verifica se está no final do arquivo
if (feof(file))
break;//quebra o loop
}


____________________________________________
https://nerdki.blogspot.com/ acessa aí vai lá, é grátis!
Capeta (demo) do meu trabalho:
https://cpusam.github.io/
"A morte é o comunismo que deu certo!"


3. Re: PROBLEMAS COM O COMANDO while(!feof(a)){

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/11/2020 - 02:07h

Salve, prezado.

Duas coisas que são muito importantes que você saiba sobre entrada e saída em C:

  1) Você deve sempre testar o valor de retorno devolvido pelas funções de leitura (e as de escrita também, especialmente quando você está escrevendo em disco e não querer correr o risco de produzir dados truncados sem perceber).

  2) As funções de diagnóstico feof() e ferror() são para ajudar a identificar a causa de falha de uma operação que já falhou. Em outras palavras, quando você segue a regra (1) acima e recebe um valor indicativo de erro, pode usar feof() para saber se a causa do tal erro foi ter tentado ultrapassar o fim de arquivo, e ferror() para saber se o erro foi causado por alguma falha operacional do sistema (tal como erro de disco, falta de espaço no disco ou em memória, perda de conexão etc.).

Essas duas regras significam que o programa abaixo está semanticamente errado, embora não possua nenhum erro de sintaxe.
#include <stdio.h>

int main(void){
char buffer[4096];
while(!feof(stdin)){
fgets(buffer, sizeof buffer, stdin);
fputs(buffer, stdout);
}
}


Note que o programa viola tanto a regra (1), ao ignorar o valor de retorno na chamada de fgets(), quanto a regra (2), ao tentar usar feof() para fazer um prognóstico, em lugar de um diagnóstico.

Se o programa acima for compilado para um executável chamado X e for executado com o comando
echo "Oi." | ./X 
a mensagem “Oi.” será impressa duas vezes, embora seja jogada na entrada do programa apenas uma vez. Mas por quê?

  • Na primeira iteração do laço de repetição:
    • A condição feof(stdin) não indica erro da operação anterior sobre stdin porque não houve operação anterior nesse arquivo, então a execução prossegue.
    • A leitura com fgets() consegue ler uma linha inteira (incluindo a marca de fim de linha). Como a leitura para assim que encontra a marca de fim de linha, não se chega ao ponto de tentar ultrapassar o fim da entrada. A função devolve um valor não-nulo para indicar que a leitura foi bem-sucedida, mas o programa ignora essa valor, já que não o testa nem o armazena em qualquer variável.
    • O conteúdo de buffer é impresso na saída.

  • Na segunda iteração do laço de repetição:
    • A condição feof(stdin) não indica erro da operação anterior sobre stdin porque a operação anterior nesse arquivo foi bem-sucedida, então a execução prossegue.
    • A leitura com fgets() imediatamente tenta ler além do fim do arquivo, sem conseguir ler efetivamente um único caráter, o que provoca um erro e faz com que um indicador de tentativa de ler além do fim de arquivo seja ligado dentro da área de dados de stdin. Como nenhum caráter foi lido, o conteúdo de buffer não é alterado (ou seja, continua com o que tinha sido posto lá durante a iteração anterior), e a função retorna um valor de erro, mas como o programa não captura nem testa esse valor de retorno, a execução simplesmente segue para a linha seguinte.
    • O conteúdo de buffer é impresso na saída. Como o conteúdo permaneceu o mesmo da iteração anterior, a linha lida anteriormente é impressa uma segunda vez.

  • Na terceira iteração do laço de repetição:
    • A condição feof(stdin) finalmente produz um valor positivo, pois a operação anterior realmente tentou ultrapassar o fim de arquivo (embora isso não tenha sido diagnosticado no momento em que ocorreu). Isso faz com que o laço de repetição seja interrompido.

Note que o mesmo programa bobo poderia ter provocado resultados ainda mais espúrios com outros tipos de entrada. Por exemplo, se você tivesse rodado com uma chamada tal como
./X < /dev/null 
(cujo efeito é colocar uma entrada sabidamente vazia), o conteúdo do laço de repetição executaria pelo menos uma vez pois, embora a entrada seja vazia, na primeira iteração ainda não se teria tentado ultrapassar o fim do arquivo; fgets() falharia logo de cara, já que a entrada é vazia, e a linha seguinte imprimiria o valor anterior de buffer, que é simplesmente desconhecido, podendo imprimir qualquer coisa, desde nada até uma quantidade indeterminada de lixo, ou até mesmo fazer o programa capotar com falha de segmentação ou outro erro semelhante. Outra possibilidade de execução danosa seria se você colocasse como entrada um arquivo que provocasse erro de sistema (por exemplo, um arquivo com estivesse alocado numa região do disco com problemas de bad sectors): nesse caso, fgets() falharia, mas não por se ter atingido o fim do arquivo, mas sim por erro operacional do sistema, e o programa poderia ficar executando indefinidamente, num loop infinito de erros.

A forma certa de fazer, portanto, seria uma que levasse em consideração as duas regras colocadas no início desta mensagem. A versão corrigida do programa, que não está sujeita a nenhum dos problemas indicados acima, teria mais ou menos a forma abaixo.
#include <stdio.h>

int main(void){
char buffer[4096];
while(fgets(buffer, sizeof buffer, stdin)){
fputs(buffer, stdout);
}
}


Note que nem ao menos foi preciso mencionar a função feof(). O teste valor de retorno de fgets() não apenas foi feito, mas é suficiente para fazer com que o programa termine sua execução tanto quando for atingido o fim dos dados de entrada (i.e. a primeira operação que tenta ir além do fim desses dados) quanto uma eventual interrupção causada não por fim desses dados, mas por algum erro do sistema.


NOTA: Embora os exemplos acima usem apenas fegts() todas as funções de entrada e saída produzem valores de retorno que indicam o grau de sucesso da operação. Se você tiver empregado outra função de leitura no seu programa, leia a documentação da tal função e faça os ajustes necessários ao seu caso.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts