Ir ao conteúdo
  • Cadastre-se

C Função lê número mal num ficheiro binário


AccioOnion

Posts recomendados

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

typedef struct Pessoa
	{
		int cc;
		char nome[51];
		char partida[11];
		char chegada[11];
		short int dia;
	} PESSOA;	

int main()
{
	int i;
	FILE* fps = fopen("okb","rb");

	PESSOA passageiro;
 
  	if (fps == NULL) 
 	{
    	 	printf("Problemas na abertura do arquivo\n");
		exit(1);
  	}

	else
	{
 	
			fread (&passageiro.cc, 4, 1, fps);
			fread (passageiro.nome, 1, 51, fps);
			fread (passageiro.partida, 1, 11, fps);
			fread (passageiro.chegada, 1, 11, fps);
			fread (&passageiro.dia, 2, 1, fps);
  		
			printf("%d ", passageiro.cc);
			for(i = 0; i < 51; i++)
			{
				printf("%c", passageiro.nome[i]);
			}
			for(i = 0; i < 11; i++)
			{
				printf("%c", passageiro.partida[i]);
			}
			for(i = 0; i < 11; i++)
			{
				printf("%c", passageiro.chegada[i]);
			}
				printf("%hd\n", passageiro.dia);
	}
	
  
 	fclose(fps);
}

Boa noite, estava aqui a fazer um trabalho e deparei-me com isto e não consigo perceber o porquê da função nao ler o que eu pretendo. Acho que deve ser algo bem simples mas como sou novo nisto não estou a conseguir detetar o que falha. É suposto esta função ler umas informações que estão num ficheiro em binário, o número do cc, nome da pessoa, local de partida e chegada do avião e dia do mês. Mas ao detetar o dia do mês a função em vez de escrever um número entre 1 - 30 escreve 256. Alguém percebe porquê?

Link para o comentário
Compartilhar em outros sites

Não use o fread pra isso, use o fscanf.

 

O que acontece com o fread é que ele lê 2 bytes e escreve esses 2 bytes no passageiro.dia. Só que, por exemplo, se você tem lá no arquivo "17" (que em binário fica 00110001 00110111), ele vai salvar no seu short o valor 00110001 00110111 (12599 em decimal, mas interpretado como 14129 porque x86 usa o formato little endian, em que o byte mais significativo fica no final, não no começo).

 

Enfim:

// apague
fread (&passageiro.dia, 2, 1, fps);
// ponha
fscanf(fps, " %hd", &passageiro.dia);

// e repare que o cc também está com o mesmo problema; eu recomendo trocar tudo por fscanf

 

Link para o comentário
Compartilhar em outros sites

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

typedef struct Pessoa
	{
		int cc;
		char nome[51];
		char partida[11];
		char chegada[11];
		short int dia;
	} PESSOA;	

int main()
{
	int i;
	FILE* fps = fopen("okb","rb");

	PESSOA passageiro;
 
  	if (fps == NULL) 
 	{
    	 	printf("Problemas na abertura do arquivo\n");
		exit(1);
  	}

	else
	{
 	
			fscanf(fps, " %hd", &passageiro.dia);
			fread (passageiro.nome, 1, 51, fps);
			fread (passageiro.partida, 1, 11, fps);
			fread (passageiro.chegada, 1, 11, fps);
			fscanf(fps, " %hd", &passageiro.dia);
  		
			printf("%d ", passageiro.cc);
			for(i = 0; i < 51; i++)
			{
				printf("%c", passageiro.nome[i]);
			}
			for(i = 0; i < 11; i++)
			{
				printf("%c", passageiro.partida[i]);
			}
			for(i = 0; i < 11; i++)
			{
				printf("%c", passageiro.chegada[i]);
			}
				printf("%hd\n", passageiro.dia);
	}
	
  
 	fclose(fps);
}

A alteração ficou assim, e o que ela lê está no print que meti no comentário de cima. Não sei se é isso que quer ver, ou se me está a pedir outra coisa.

Link para o comentário
Compartilhar em outros sites

Isso mesmo, obrigado. Já vi o problema! Quem criou o arquivo conseguiu (não faço ideia de como) misturar little endian com big endian.

okb.png.72dca332c4d7111506c87511dc92131f.png

O cc estava correto do jeito que você pos porque está em little endian no arquivo. O dia/data precisa inverter os bytes. Deve ficar assim o código:

			fread (&passageiro.cc, 4, 1, fps);
			fread (passageiro.nome, 1, 51, fps);
			fread (passageiro.partida, 1, 11, fps);
			fread (passageiro.chegada, 1, 11, fps);
			fread (&passageiro.dia, 2, 1, fps);

			// inverte os bytes do dia -- assumindo arquitetura que usa little endian
			passageiro.dia = ((passageiro.dia&255)<<8) + (passageiro.dia>>8);

Edit: um outro detalhe é que aparenta ter um último byte 00 após cada entrada (o que por enquanto não dá problema, mas vai dar quando você fizer um loop pra pegar todos os passageiros). Nesse caso não esqueça de dar um último fread pegando e descartando um byte (bom, fica de sugestão pra quando der erro, não se preocupe em entender o problema até ele aparecer).

 

Edit: assumindo que o primeiro byte do dia é sempre 0 (afinal, por que não seria?) um jeito mais portável (porque não tem que inverter bytes) é:

			fread (&passageiro.cc, 4, 1, fps);
			fread (passageiro.nome, 1, 51, fps);
			fread (passageiro.partida, 1, 11, fps);
			fread (passageiro.chegada, 1, 11, fps);

			// descarta um byte, que é sempre 0
			char dia;
			fread (&dia, 1, 1, fps);
			// lê o dia
			fread (&dia, 1, 1, fps); // não leia direto pro passageiro.dia pois
			passageiro.dia = dia; // se ele não estiver zerado vai ficar errado

 

Link para o comentário
Compartilhar em outros sites

Olá outra vez, entretanto estive a ler o mesmo ficheiro mas desta vez em formato de texto e apareceu no final aquela linha com uns caracteres estranhos, alguem sabe porquê?

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

int main ()
{
	int contador;
	long int nr;
	char nome[51], partida[11], chegada[11], ch;
	short int dia;	

	FILE* fp = fopen("ok","r");
	if(fp == NULL)
	{
		printf("Impossivel abrir o ficheiro");
		exit(1);
	}

	while(fgetc(fp) != EOF)
	{		

		fscanf(fp, " %ld", &nr);
		printf("%ld ", nr);

		contador = 0;
		while(contador < 51)
			{
				ch = fgetc(fp);
				nome[contador] = ch;
				printf("%c", ch);
				contador++;
				
			}
			
		contador = 0;
		while(contador < 11)
			{
				ch = fgetc(fp);
				partida[contador] = ch;
				printf("%c", ch);
				contador++;
			}

		contador = 0;
		while(contador < 11)
			{
				ch = fgetc(fp);
				chegada[contador] = ch;
				printf("%c", ch);
				contador++;
			}

		fscanf(fp, " %hd", &dia);
		printf("%hd\n", dia);
	}

	fclose(fp);
}

 

texto.png

Link para o comentário
Compartilhar em outros sites

Teria como enviar o ficheiro no formato texto? Pela forma que você está usando o fgetc na condição do while, tem algum caractere extra em cada linha, certo? Se o seu arquivo estiver terminando com uma quebra de linha, quando você der fgetc ele pega o '\n' em vez de dar EOF. A solução que eu posso sugerir sem olhar o arquivo é:

    // ... resto do código ...
    while(fgetc(fp) != EOF && fscanf(fp, " %ld", &nr) != EOF)
    {		
        // move o fscanf &nr daqui pra condição do while
        // ... resto do código ...

 

Link para o comentário
Compartilhar em outros sites

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

typedef struct Pessoa
	{
		int cc;
		char nome[51];
		char partida[11];
		char chegada[11];
		short int dia;
	} PESSOA;

int main ()
{
	PESSOA passageiro;
	int contador;
	char ch;	

	FILE* fp = fopen("ok","r");
	if(fp == NULL)
	{
		printf("Impossivel abrir o ficheiro");
		exit(1);
	}


	while(fgetc(fp) != EOF && fscanf(fp, "%d", &passageiro.cc))
	{	
		printf("%d ", passageiro.cc);

		contador = 0;
		while(contador < 51)
			{
				ch = fgetc(fp);
				passageiro.nome[contador] = ch;
				printf("%c", passageiro.nome[contador]);
				contador++;
				
			}
			
		contador = 0;
		while(contador < 11)
			{
				ch = fgetc(fp);
				passageiro.partida[contador] = ch;
				printf("%c", passageiro.partida[contador]);
				contador++;
			}

		contador = 0;
		while(contador < 11)
			{
				ch = fgetc(fp);
				passageiro.chegada[contador] = ch;
				printf("%c", passageiro.chegada[contador]);
				contador++;
			}

		fscanf(fp, " %hd", &passageiro.dia);
		printf("%hd\n", passageiro.dia);
	}

	fclose(fp);
}

o código agora está assim mas continua a dar o mesmo.ok.zip

O ficheiro é este:

Link para o comentário
Compartilhar em outros sites

Outra coisa, eu abri o arquivo que você mandou aqui, e ele não começa com quebra de linha, começa direto com o cc. Então do jeito que você fez está perdendo o primeiro digito do cc do primeiro passageiro. Mude o while pra ser apenas:

// sim, sem o fgetc... o espaço antes do %d já vai remover
// o \n e outras porcarias pra você.
while(fscanf(fp, " %d", &passageiro.cc) != EOF)

 

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!