Jump to content
PsySc0rpi0n

Exercício - Problema com loop infinito

Recommended Posts

PsySc0rpi0n

Boas novamente...

Na última segunda feira estivemos a fazer o seguinte exercício:

Escreva um programa que leia valores inteiros positivos e os guarde num ficheiro binário. O fim da introdução é sinalizado pela introdução de um negativo. Depois, o programa deve criar dois ficheiros: um com os nºs pares e outro com os nºs impares.

Eu fiz de uma maneira mas acabei por ficar encalhado num loop infinito.

Criei algumas funções e nessas funções passei o ponteiro para o FILE.

A prof. disse que desconfiava que fosse por estar a passar um file pointer porque não é recomendado fazê-lo.

Neste momento não tenho aqui o code comigo mas mais logo ou amanhã já aqui o coloco.

Quanto à passagem do file pointer para diversas funções, há mesmo inconvenientes?

O loop infinito que obtive foi na função que mostrava o ficheiro onde guardei os números pares e ímpares. É uma função que recebe dois file pointers, para o file dos pares e para o file dos ímpares, e depois lê o file (binário) e apresenta no ecrã os valores lá guardados em cada um dos files.

os respectivos fopens estão na função main... Mas amanhã eu coloco o code...

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Nao. Nao ha problema nenhum em passar um ponteiro para FILE: é isso que fazem muitas funcoes declaradas no header <stdio.h>.

Assim sem mais informacao, eu aposto que estas a fazer um feof() errado.

A maior parte do uso de feof() em programas "basicos" esta errada!

O feof() nao serve para verificar se a proxima leitura vai dar erro por nao haver dados.

O feof() serve para ajudar a identificar a causa do ultimo erro de leitura; se nao houve erro de leitura, o uso de feof() esta pura e simplesmente errado.

Ou seja: o uso correcto de feof() pressupoe que se tenha detectado um erro de leitura antes desse mesmo uso.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Bom dia...

Então o code é este e obtenho um loop infinito na função LeParesImpares()... E não é o único problema, mas vamos por partes...

#include <stdio.h>
#include <stdlib.h>

void GravaFicheiro(FILE *pfile, int *numeros) {
fwrite (numeros, sizeof(int), 1, pfile);
}
void GravaPar(FILE *pfpar, int *numeros) {
 fwrite (&numeros, sizeof(int), 1, pfpar);
}
void GravaImpar(FILE *pfileimpar, int *numeros) {
fwrite (&numeros, sizeof(int), 1, pfileimpar);
}

void LeParesImpares(FILE *fpares, FILE *fimpares) {
int numpares, numimpares;
while (!(fread(&numpares, sizeof(int), 1, fpares)))
 printf ("\nNúmeros pares:%d\t", numpares);

while (!(fread(&numimpares, sizeof(int), 1, fimpares)))
 printf("\nImpares:%d\t", numimpares);
}
int main(void) {
int numeros;
FILE *pfile, *pfilepar, *pfileimpar;
 if ((pfile = fopen ("num.dat", "w+b")) == NULL) {
	 printf ("Erro a abrir o ficheiro!\n");
	 exit (0);
 }
 if ((pfilepar = fopen ("par.dat", "w+b")) == NULL) {
	 printf ("Erro a abrir o ficheiro!\n");
	 exit (1);
 }
 if ((pfileimpar = fopen ("impar.dat", "w+b"))== NULL) {
	 printf ("Erro ao abrir ficheiro!\n");
	 exit (2);
 }
do {
 printf ("Introduza números inteiros:\n");
 printf ("Introduza um número negativo para sair:\n");
 scanf ("%d", &numeros);
 if (numeros >= 0)
	 //fwrite (&numeros, sizeof(int),1,pfile);
	 GravaFicheiro (&pfile, &numeros);
 if (!(numeros%2))
	 //fwrite(&numeros, sizeof(int),1,pfilepar);
	 GravaPar (&pfilepar, &numeros);
 else
	 fwrite (&numeros, sizeof(int),1,pfileimpar);
	 //GravaImpar (&pfileimpar, &numeros);
} while (numeros >= 0);
LeParesImpares (pfilepar, pfileimpar);
fclose(pfile);
fclose(pfilepar);
fclose(pfileimpar);
getchar ();
return 0;
}

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Primeiro: liga os warnings do teu compilador.

Alguns dos valores que passas da funcao main() para as outras funcoes tem o tipo errado. O compilador bem configurado pode-te avisar disso.

Sugestao: nao uses o operador ! com o valor devolvido pela funcao fread().

O teu problema da funcao LeParesImpares() é estares constantemente a tentar ler depois do fim do ficheiro. A funcao devolve 0 (zero) e o operador ! torna esse valor verdade e o ciclo nao termina.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

pmg, o gcc não me dá warnings nenhuns... Que cinfigurações me faltam???

Quanto ao fread, ter ali o !, não é o mesmo que fazer != 0???

Neste momento tenho o code assim:

#include <stdio.h>
#include <stdlib.h>

void GravaFicheiro(FILE *pfile, int *numeros) {
  fwrite (numeros, sizeof(int), 1, pfile);
}
void GravaPar(FILE *pfpar, int *numeros) {
  fwrite (&numeros, sizeof(int), 1, pfpar);
}
void GravaImpar(FILE *pfileimpar, int *numeros) {
  fwrite (&numeros, sizeof(int), 1, pfileimpar);
}

void LeParesImpares(FILE *fpares, FILE *fimpares) {
  int numpares, numimpares;
  while (!feof (fpares)) {
  fread(&numpares, sizeof(int), 1, fpares);
  printf ("\nNúmeros Pares:%d\t", numpares);
  }
  putchar ('\n');
  while (!feof (fimpares)) {
  fread(&numimpares, sizeof(int), 1, fimpares);
  printf("\nNúmeros Impares:%d\t", numimpares);
  }
  putchar ('\n');
}
int main(void) {
  int numeros;
  FILE *pfile, *pfilepar, *pfileimpar;
  if ((pfile = fopen ("num.dat", "w+b")) == NULL) {
	 printf ("Erro a abrir o ficheiro!\n");
	 exit (0);
  }
  if  ((pfilepar = fopen ("par.dat", "w+b")) == NULL) {
	 printf ("Erro a abrir o ficheiro!\n");
	 exit (1);
  }
  if ((pfileimpar = fopen ("impar.dat", "w+b"))== NULL) {
	 printf ("Erro ao abrir ficheiro!\n");
	 exit (2);
  }
  do {
  printf ("Introduza números inteiros:\n");
  printf ("Introduza um número negativo para sair:\n");
  scanf ("%d", &numeros);
  if (numeros >= 0)
	 fwrite (&numeros, sizeof(int),1,pfile);
	 //GravaFicheiro (&pfile, &numeros); debugging
  if (!(numeros%2))
	 fwrite(&numeros, sizeof(int),1,pfilepar); debugging
	 //GravaPar (&pfilepar, &numeros); debugging
  else
	 fwrite (&numeros, sizeof(int),1,pfileimpar);
	 //GravaImpar (&pfileimpar, &numeros);
  } while (numeros >= 0);
  LeParesImpares (pfilepar, pfileimpar);
  fclose(pfile);
  fclose(pfilepar);
  fclose(pfileimpar);
getchar ();
return 0;
}

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
HappyHippyHippo

pmg, o gcc não me dá warnings nenhuns... Que cinfigurações me faltam???

não sei, mas provavelmente o -Wall, -pedantic, -Werror

Quanto ao fread, ter ali o !, não é o mesmo que fazer != 0???

o fread retorna o número de elementos lidos, se pedires para ler 40 elementos e retornar 20, como vai verificar o erro ocorrido com essa comparação ?


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
PsySc0rpi0n

não sei, mas provavelmente o -Wall, -pedantic, -Werror

o fread retorna o número de elementos lidos, se pedires para ler 40 elementos e retornar 20, como vai verificar o erro ocorrido com essa comparação ?

Já alterei... Vou testar agora...

Acho que tenho essas 3 flags no alias do .bashrc

Edited;

Adicionei o -Werror mas continua a não dar qualquer warning... Os outros já os tinha...

alias agcc='gcc -Wall -Wextra -Werror -pedantic -std=c99 -lm'

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Ok, já sei o que se passava... Estavam ali uns & a mais mas foi na aula que estivemos a tentar perceber porque não conseguia sair do loop infinito e andámos a inventar...

Já retirei e já compilei de novo sem erros...

Mas o resultado ainda não é o esperado...

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
HappyHippyHippo

antes de mais : o que tens não é o pedido no exercício !!!

responde a esta questão : onde se encontra o ponteiro interno dos ficheiros quando chamas a função LeParesImpares ?


IRC : sim, é algo que ainda existe >> #p@p

Share this post


Link to post
Share on other sites
pmg

Quanto ao fread, ter ali o !, não é o mesmo que fazer != 0???

Nao! Por isso mesmo sugeri que nao usasses o !

A mim faz-me sempre confusao usar o ! com coisas que nao sao "booleanos"

if (x) {}      /* A */
if (x != 0) {} /* A */

if (!x) {}     /* B */
if (x == 0) {} /* B */

if (fread(...) == 1) {} /* nem A nem B */
if (fread(...) != 1) {} /* nem A nem B */


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

O code neste momento está assim:

#include <stdio.h>
#include <stdlib.h>

void GravaFicheiro(FILE *pfile, int numeros) {
  fwrite (&numeros, sizeof(int), 1, pfile);
}
void GravaPar(FILE *pfpar, int numeros) {
  fwrite (&numeros, sizeof(int), 1, pfpar);
}
void GravaImpar(FILE *pfileimpar, int numeros) {
  fwrite (&numeros, sizeof(int), 1, pfileimpar);
}
void LeParesImpares(FILE *fpares, FILE *fimpares) {
  int numpares, numimpares;
  while (!feof(fpares)) {
  fread(&numpares, sizeof(int), 1, fpares);
  printf ("\nNúmeros Pares:%d\t", numpares);
  }
  putchar ('\n');
  while (!feof(fimpares)) {
  fread(&numimpares, sizeof(int), 1, fimpares);
  printf("\nNúmeros Impares:%d\t", numimpares);
  }
  putchar ('\n');
}
int main(void) {
  int numeros;
  FILE *pfile, *pfilepar, *pfileimpar;
  if ((pfile = fopen ("num.dat", "w+b")) == NULL) {
	 printf ("Erro a abrir o ficheiro!\n");
	 exit (0);
  }
  if  ((pfilepar = fopen ("par.dat", "w+b")) == NULL) {
	 printf ("Erro a abrir o ficheiro!\n");
	 exit (1);
  }
  if ((pfileimpar = fopen ("impar.dat", "w+b"))== NULL) {
	 printf ("Erro ao abrir ficheiro!\n");
	 exit (2);
  }
  do {
  printf ("Introduza números inteiros:\n");
  printf ("Introduza um número negativo para sair:\n");
  scanf ("%d", &numeros);
  if (numeros >= 0){
	 //fwrite (&numeros, sizeof(int),1,pfile);
	 GravaFicheiro (pfile, numeros);
  if (!(numeros%2))
	 //fwrite(&numeros, sizeof(int),1,pfilepar);
	 GravaPar (pfilepar, numeros);
  else
	 //fwrite (&numeros, sizeof(int),1,pfileimpar);
	 GravaImpar (pfileimpar, numeros);
  }
  } while (numeros >= 0);

  printf ("Posição do filepointer par %ld\n", ftell(pfilepar));
  printf ("Posição do filepointer impar %ld\n", ftell(pfileimpar));
  printf ("Posição do filepointer %ld\n", ftell(pfile));
  LeParesImpares (pfilepar, pfileimpar);
  fclose(pfile);
  fclose(pfilepar);
  fclose(pfileimpar);
getchar ();
return 0;
}

Os file pointers estão:

Posição do filepointer par 20

Posição do filepointer impar 20

Posição do filepointer 40

Já está quase perfeito... Só está a repetir o último valor inserido... Faltava o rewind!!!

Uma outra questão: qual função usar para colocar o filepointer no início do file? fseek ou rewind?

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Agora tens o erro que eu apostava no principio do thread: erro no uso da funcao feof(); embora o teu codigo nao faca ciclos devido ao erro.

Usa o valor de retorno da funcao fread() para saber se deves parar o ciclo ou nao. Usar o feof() para esse efeito esta errado.

Uma outra questão: qual função usar para colocar o filepointer no início do file? fseek ou rewind?

fseek() com os argumentos correctos é muito, muito parecido com rewind().


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Então uso o quê? Assim:

while ((fread(&numeros, sizeof(int), 1, fpointer)) !=0)

É que não percebi bem como usar o valor de retorno do fread!

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

O fread() é assim que funciona:

M = fread(A, S, N, F);

O fread() vai tentar ler N elementos, cada um com S bytes, de F e mete-los em A.

O valor devolvido (M) tem que ser entre 0 (zero) e N.

Se correr tudo bem, vai ser N.

Se M < N isso quer dizer que o fread() nao conseguiu ler tudo o que lhe foi pedido.

A razao de nao ter lido tudo pode ser por erro (falha no disco, falha na rede, tirar a disquete, ...) ou por falta de dados. Nao é possivel determinar, apenas com o fread(), a razao da falha ... e, em programas "basicos", nem sequer é preciso.

Portanto, usa o fread() testando com o numero de elementos pedidos

while (fread(&numeros, sizeof(int), 1, fpointer) == 1) {
   /* ... */
}

Neste caso especifico, o fread() ou devolve 1 (indicando que esta tudo bem) ou 0 (indicando que nao esta tudo bem). Ao devolver 0 acabas o ciclo. Se te interessar fazer alguma coisa diferente consoante o fread() tenha falhado por falha no disco ou por falta de dados podes usar feof() ou ferror() e prosseguir com a gestao de erros a partir dai.

  • Vote 1

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Ok... Thanks... Esta explicação é exemplar... Muito obrigado!

Outro pormenor é que no while dos números pares, ele não está a respeitar o \t ... Haverá razão para isso?

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Este while?

   while (!feof(fpares)) {
         fread(&numpares, sizeof(int), 1, fpares);
         printf ("\nNúmeros Pares:%d\t", numpares);
  }

Estas, talvez, a ignorar o efeito do \n?

Sugestao: en vez de pores o \n no principio (ou no meio) dos printfs, mete-o no fim.

Edited by pmg

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Não percebi a tua pergunta mas o que eu pretendia era colocar um espaço antes do primeiro printf dos pares e um antes do primeiro printf dos ímpares para separar a lista dos pares dos ímpares...

O code neste momento está assim:

#include <stdio.h>
#include <stdlib.h>

void GravaFicheiro(FILE *pfile, int numeros) {
  fwrite (&numeros, sizeof(int), 1, pfile);
}
void GravaPar(FILE *pfpar, int numeros) {
  fwrite (&numeros, sizeof(int), 1, pfpar);
}
void GravaImpar(FILE *pfileimpar, int numeros) {
  fwrite (&numeros, sizeof(int), 1, pfileimpar);
}
void LeParesImpares(FILE *fpares, FILE *fimpares) {
  int numpares, numimpares;

  rewind(fpares);
  rewind(fimpares);
  while((fread(&numpares, sizeof(int), 1, fpares)) == 1)
  printf ("Números Pares:%d\t", numpares);

  putchar('\n');

  while((fread(&numimpares, sizeof(int), 1, fimpares)) == 1)
  printf("Números Impares:%d\t", numimpares);

  putchar('\n');
}
int main(void) {
  int numeros;
  FILE *pfile, *pfilepar, *pfileimpar;
  if ((pfile = fopen ("num.dat", "w+b")) == NULL) {
	 printf("Erro a abrir o ficheiro!\n");
	 exit(0);
  }
  if  ((pfilepar = fopen ("par.dat", "w+b")) == NULL) {
	 printf("Erro a abrir o ficheiro!\n");
	 exit(1);
  }
  if ((pfileimpar = fopen ("impar.dat", "w+b"))== NULL) {
	 printf("Erro ao abrir ficheiro!\n");
	 exit(2);
  }
  do {
  printf ("Introduza números inteiros:\n");
  printf ("Introduza um número negativo para sair:\n");
  scanf ("%d", &numeros);
  if(numeros >= 0){
	 GravaFicheiro (pfile, numeros);
  if(!(numeros%2))
	 GravaPar (pfilepar, numeros);
  else
	 GravaImpar (pfileimpar, numeros);
  }
  } while(numeros >= 0);

  printf("Posição do filepointer par %ld\n", ftell(pfilepar));
  printf("Posição do filepointer impar %ld\n", ftell(pfileimpar));
  printf("Posição do filepointer %ld\n", ftell(pfile));
  LeParesImpares(pfilepar, pfileimpar);
  fclose(pfile);
  fclose(pfilepar);
  fclose(pfileimpar);
getchar();
return 0;
}

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Cada putchar('\n') do teu codigo acime termina a linha onde é colocado.

Por exemplo

"Números Pares:12\tNúmeros Pares:42\t"

depois do putchar fica assim

"Números Pares:12\tNúmeros Pares:42\t\n"

e os numeros impares vem logo a seguir

"Números Pares:12\tNúmeros Pares:42\t\nNúmeros Impares:13\t"

Em vez de um '\n' mete 2

"Números Pares:12\tNúmeros Pares:42\t\n\nNúmeros Impares:13\t"
/* ------------------------------ -> ^^^^ 2 ENTERs */


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Queres dizer, repetir o puchar('\n'); em cada um dos sítios onde o tenho agora?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Queres dizer, repetir o puchar('\n'); em cada um dos sítios onde o tenho agora?

Experimenta e tira as tuas conclusoes.

Acho que nao vai ser bem o que pretendes, mas depressa adaptas o programa para o que queres :)


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Continua igual... A linha dos pares não fica separada por \t

Números Pares:2 Números Pares:4 Números Pares:6 Números Pares:8 Números Pares:10

Números Impares:1....Números Impares:3....Números Impares:5....Números Impares:7....Números Impares:9

Aqui não se vê mas a linha dos ímpares tem espaçamentos e a dos pares não tem...

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Comprimento da string "Numeros Pares:6" = 15

Para chegar ao tabulador (a 8, 16, 24, 32, 40, ...) chega um espaco.

Experimenta com numeros pares maiores que 11

Comprimento da string "Numeros Pares:16" = 16 === precisa de 8 espacos para chegar ao tabulador seguinte

Edited by pmg

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Com números maiores que 11 já deu, mas não percebi porquê...


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites
pmg

Com números maiores que 11 já deu, mas não percebi porquê...

Porque o TAB (o '\t') faz com que a impressao comece no tabulador mais proximo seguinte.

Os tabuladores normais estao definidos a cada 8 colunas (8, 16, 24, 32, ...).

Se imprimes 15 caracteres e um tabulador, a proxima impressao sera na coluna 16 (com um espaco)

Se imprimes 16 caracteres e um tabulador, a proxima impressao sera na coluna 24 (com 8 espacos)

Se imprimes 17 caracteres e um tabulador, a proxima impressao sera na coluna 24 (com 7 espacos)


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Share this post


Link to post
Share on other sites
PsySc0rpi0n

Epá isso é mesmo estranho e medonho... Que raio de tanga essa das tabulações... Não faz sentido nenhum, mas enfim!


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.