View Full Version : Criar ficheiro com struct em C


Catrabinas
31-01-2008, 16:32
Boas pessoal..

a minha duvída é a seguinte: eu tenho um programa em C com struct e tenho de o abrir e guardar em ficheiro.. o programa é este:

#include <stdio.h>
#include <conio.h>
typedef struct {int Dia,Mes,Ano;} DATA;
typedef struct pessoa
{
char Nome[100];
int Idade;
int Salario;
DATA Nasc;
} PESSOA;

void ler_pessoa(PESSOA *ptr)
{
printf("Introduza o nome: "); gets(ptr->Nome);
printf("Introduza a idade: "); scanf("%d", &ptr->Idade);
printf("Introduza o salario: "); scanf("%d", &ptr->Salario);
printf("Introduza o dia nascimento: "); scanf("%d", &ptr->Nasc.Dia);
printf("Introduza o mes nascimento: "); scanf("%d", &ptr->Nasc.Mes);
printf("Introduza o ano nascimento: "); scanf("%d", &ptr->Nasc.Ano);
}
void Mostrar(struct pessoa x)
{
printf("Nome : %s \n",x.Nome);
printf("Idade : %d \n",x.Idade);
printf("Salario : %d \n",x.Salario);
printf("Data Nasc. : %d/%d/%d \n",x.Nasc.Dia,x.Nasc.Mes,x.Nasc.Ano);
}
void main(void)
{
struct pessoa p;
ler_pessoa(&p);
Mostrar(p);
abrir_fich(&p);
getch();
}

alguem sabe como ficaria o programa?

AragTey
31-01-2008, 19:44
FILE *f = fopen(nome_do_fich, "wb"); // abrir escrita do ficheiro em binário
if (f != NULL)
{
fwrite(&p, sizeof(pessoa), 1, f); // escrever uma estrutura do tipo pessoa
fclose(f);
}

petersaints
31-01-2008, 20:15
FILE *f = fopen(nome_do_fich, "wb"); // abrir escrita do ficheiro em binário
if (f != NULL)
{
fwrite(&p, sizeof(pessoa), 1, f); // escrever uma estrutura do tipo pessoa
fclose(f);
}



Yah eu já fiz isso num projecto de C uma vez (perdi a source :( entretanto). Mas acho que usei fprintf e fscanf para escrever e ler mas este método parece ser mais straightforward e para ler basta usar fread? Já agora porque é que tem que ser em binário? É coisa que nunca percebi... qual a diferença de gravar em binário ou em texto?

AragTey
31-01-2008, 20:23
Yah eu já fiz isso num projecto de C uma vez (perdi a source :( entretanto). Mas acho que usei fprintf e fscanf para escrever e ler mas este método parece ser mais straightforward e para ler basta usar fread? Já agora porque é que tem que ser em binário? É coisa que nunca percebi... qual a diferença de gravar em binário ou em texto?

Não tem de ser em binário, mas no caso de estruturas penso que é mais facil, porque apenas gravas o que tens em memária, sem te preocupares com o tipo de variável. Alem disso em binário ocupa menos espaço. Em binário não consegues perceber o que está no ficheiro e em texto consegues.

Sim basta usar fread para ler, mas tens de saber a quantidade que vais ler, isto é, se por exemplo se graver um array de struct pessoa tens de gravar primeiro um numero com a quantidade, para depois leres isso tudo.

petersaints
31-01-2008, 20:41
Sim basta usar fread para ler, mas tens de saber a quantidade que vais ler, isto é, se por exemplo se graver um array de struct pessoa tens de gravar primeiro um numero com a quantidade, para depois leres isso tudo.

Como assim? Esse número seria gravado como?

P.S.:
fwrite(&p, sizeof(pessoa), 1, f);Os argumentos do fwrite querem dizer o que?
&p é o nome da variável pessoa p?
o sizeof é para saber o tamanho suponho
o 1 é o que? só uma entrada?
e o f é o pointer do ficheiro certo?

MadOnion
31-01-2008, 20:46
Yah eu já fiz isso num projecto de C uma vez (perdi a source :( entretanto). Mas acho que usei fprintf e fscanf para escrever e ler mas este método parece ser mais straightforward e para ler basta usar fread? Já agora porque é que tem que ser em binário? É coisa que nunca percebi... qual a diferença de gravar em binário ou em texto?

Em binário, o sistema operativo entende que "cada linha do ficheiro" contém uma struct. O que está dentro da struct não interessa, interessa é que contem uma struct.
Fica complicado se guardares num ficheiro de texto, todos os campos de uma struct, é completamente ilegivél.
Grava-se para um ficheiro binário uma struct, depois retira-se desse ficheiro binário a mesma struct, "desdobra-se" dentro do programa e dás o destino que bem entenderes.
Para imprimir o seu conteúdo, podes usar o fprintf, em stdout ou para outro ficheiro de formato texto(e portanto, legivel).

Edit:

#include <stdio.h>

size_t
fread(void *restrict ptr, size_t size, size_t nitems,
FILE *restrict stream);

size_t
fwrite(const void *restrict ptr, size_t size, size_t nitems,
FILE *restrict stream);


Exacto os parametros querem dizer isso.
O apontador para a struct onde vais guardar a struct lida do ficheiro.
O tamanho da struct.
O número de itens a ser lido
E o filepointer.

petersaints
31-01-2008, 21:09
Yeah I got it ;) Só uma cena o número de itens a ser lido vai depender do tamanho da base de dados (por assim dizer) se eu definir um vector, por exemplo struct pessoa p[100], da estrutura como sei quanto estão guardados? (NO EXEMPLO APRESENTADO ELE APENAS TINHA 1 PESSOA)

Este thread nem é meu mas fez-me relembrar e despertar a curiosidade :P

MadOnion
31-01-2008, 21:27
int contador = 0;

/*O fread quando não tiver mais nada para ler, devolve -1, se não estou em erro*/
while (contador < 100 && (fread(&p, sizeof(pessoa), 1, f) != -1)) {

(...)
}


A leitura é feita um por um, ele pára quando o contador chegar ao fim, ou quando o ficheiro estiver sem dados.

AliFromCairo
31-01-2008, 22:09
Yeah I got it ;) Só uma cena o número de itens a ser lido vai depender do tamanho da base de dados (por assim dizer) se eu definir um vector, por exemplo struct pessoa p[100], da estrutura como sei quanto estão guardados? (NO EXEMPLO APRESENTADO ELE APENAS TINHA 1 PESSOA)

Este thread nem é meu mas fez-me relembrar e despertar a curiosidade :P

Sim, é isso.


int contador = 0;

/*O fread quando não tiver mais nada para ler, devolve -1, se não estou em erro*/
while (contador < 100 && (fread(&p, sizeof(pessoa), 1, f) != -1)) {

(...)
}


A leitura é feita um por um, ele pára quando o contador chegar ao fim, ou quando o ficheiro estiver sem dados.

Ler um a um não é particularmente eficiente. É para evitar isso que serve o terceiro argumento da função. Para além disso, no código que colocaste, vais ficar apenas com o último elemento, na primeira posição, que não é o que se pretende :007:. Para funcionar correctamente, o primeiro argumento deveria ser &p + contador * sizeof(pessoa).

MadOnion
31-01-2008, 22:44
Sim, é isso.



Ler um a um não é particularmente eficiente. É para evitar isso que serve o terceiro argumento da função. Para além disso, no código que colocaste, vais ficar apenas com o último elemento, na primeira posição, que não é o que se pretende :007:. Para funcionar correctamente, o primeiro argumento deveria ser &p + contador * sizeof(pessoa).

Na minha abordagem, o &p é uma struct auxiliar que contém cada struct lida actualmente.
Posteriormente essa struct seria guardada/copiada para um vector de structs, no indice i, e continuava com a leitura até a guarda do while ser falsa.
Eu não sei até que ponto o size_t nitems é eficiente, ou seja, se eu disser que quero guardar 100, e o ficheiro só conter 20 structs, foi uma situação que nunca testei, mas também é facilmente explorável.

AragTey
31-01-2008, 23:34
Se se usar um vector(ou array) para guardar a informação a leitura e escrita fica mais simplificada, ficando algo como:


//write
int size = vect_pessoas.size();
putw(size, f);
fwrite(pessoas.begin(), sizeof(pessoa), size, f);
fclose();

// read algo semelhante a:
size = getw(f);
vect_pessoas.resize(size);
if (size > 0)
if (fread(vect_pessoas.begin(), sizeof(pessoa), size, f) != size)
fclose(f);


Simplificando a escrita\leitura comeca na posicao de memoria onde está o inicio do vector e reserva na memoria, size*sizeof(pessoa) para a escrita\leitura.

Catrabinas
12-02-2008, 10:16
Obrigado a todos pela ajuda! Já consegui:001:

Faulk_08
07-07-2008, 16:01
Obrigado a todos pela ajuda! Já consegui:001:
Boas,
Eu também estou com o mesmo problema em trabalhar com estruturas com ficheiros.
Será que me podias disponibilizar o teu programa na totalidade resolvido para poder tirar as minhas duvidas??
Agradecia imenso
Obrigado

Mr. Brightside
07-07-2008, 20:32
Boas,
Eu também estou com o mesmo problema em trabalhar com estruturas com ficheiros.
Será que me podias disponibilizar o teu programa na totalidade resolvido para poder tirar as minhas duvidas??
Agradecia imenso
Obrigado

Não será melhor dizeres quais as dúvidas que tens e nós tentamos ajudar?

Faulk_08
07-07-2008, 21:57
Não será melhor dizeres quais as dúvidas que tens e nós tentamos ajudar?


typedef struct {int Dia,Mes,Ano;}Data;
typedef struct pessoal
{
char Nome[100];
char Genero[100];
Data Nascimento;
int Nmc;
int Nmf;
}Agente;
void criar_agente(char nometxt[]){
FILE *file = fopen(nometxt, "ab");
if (file != NULL)
{
printf("Introduza o nome: ");
gets(ptr->Nome);
printf("Introduza o genero: ");
gets(ptr->Genero);
printf("Introduza o dia nascimento: ");
scanf("%d", &ptr->Nasc.Dia);
printf("Introduza o mes nascimento: ");
scanf("%d", &ptr->Nasc.Mes);
printf("Introduza o ano nascimento: ");
scanf("%d", &ptr->Nasc.Ano);
printf("Introduza o numero de missoes concluidas com sucesso: ");
scanf("%d", &ptr->Nmc);
printf("Introduza o numero de missoes falhadas: ");
scanf("%d", &ptr->Nmf);

}


Como poderei agora escrever num ficheiro?????

AragTey
08-07-2008, 09:37
Boas é semelhante ao que já foi explicado aqui nesta thread ... dá uma vista de olhos...

Faulk_08
08-07-2008, 20:59
Boas é semelhante ao que já foi explicado aqui nesta thread ... dá uma vista de olhos...
Pois eu ja dei uma vista de olhos mas nao me consegui resolver o problema???
Ajudem-me....

AragTey
09-07-2008, 08:19
FILE *f = fopen(nome_do_fich, "wb"); // abrir escrita do ficheiro em binário
if (f != NULL)
{
fwrite(&p, sizeof(pessoa), 1, f); // escrever uma estrutura do tipo pessoa
fclose(f);
}


Abres o ficheiro de escrita em modo binario e depois usas o fwrite onde passsa como argumentos a estrutura que queres escrever, o tamanho, dessas estrutura a quantidade de estruturas desse tipo que vais escrever e por fim o ponteiro para o ficheiro.

http://www.cplusplus.com/reference/clibrary/cstdio/fwrite.html

EDIT: no teu caso em vez da estrutura pessoa tem pessoal.

Faulk_08
09-07-2008, 11:28
Abres o ficheiro de escrita em modo binario e depois usas o fwrite onde passsa como argumentos a estrutura que queres escrever, o tamanho, dessas estrutura a quantidade de estruturas desse tipo que vais escrever e por fim o ponteiro para o ficheiro.

http://www.cplusplus.com/reference/clibrary/cstdio/fwrite.html

EDIT: no teu caso em vez da estrutura pessoa tem pessoal.


typedef struct {int Dia,Mes,Ano;}Data;
typedef struct pessoal
{
char Nome[100];
char Genero[100];
Data Nascimento;
int Nmc;
int Nmf;
}Agente;
void criar_agente(char nometxt[]){
FILE *file = fopen(nometxt, "ab");
if (file != NULL)
{
printf("Introduza o nome: ");
gets(&ptr->Nome);
printf("Introduza o genero: ");
gets(&ptr->Genero);
printf("Introduza o dia nascimento: "); scanf("%d", &ptr->Nasc.Dia);
printf("Introduza o mes nascimento: "); scanf("%d", &ptr->Nasc.Mes);
printf("Introduza o ano nascimento: "); scanf("%d", &ptr->Nasc.Ano);
printf("Introduza o numero de missoes concluidas com sucesso: ");
scanf("%d", &ptr->Nmc);
printf("Introduza o numero de missoes falhadas: ");
scanf("%d", &ptr->Nmf);
fwrite(&ptr, sizeof(Agente), 1, file);
fclose(file);
}

}

Ja modifiquei so que mesmo assim da-me erro na linha abaixo

printf("Introduza o nome: ");
gets(&ptr->Nome);????????

Baderous
09-07-2008, 11:49
Não declaraste o ptr em lado nenhum.

Faulk_08
09-07-2008, 21:29
Não declaraste o ptr em lado nenhum.
ya e como vou declarar isso???

Baderous
09-07-2008, 21:37
Dentro da função, tal e qual como quando declaras outra variável.

Faulk_08
10-07-2008, 11:12
Dentro da função, tal e qual como quando declaras outra variável.
Mas vou declara-la de que tipo????

Baderous
10-07-2008, 11:14
Sendo prt um apontador tens que declarar que ele aponta para o tipo da estrutura.

AragTey
10-07-2008, 11:15
Mas vou declara-la de que tipo????

do tipo da tua estrutura pessoal:

struct pessoal ptr;

Baderous
10-07-2008, 11:18
do tipo da tua estrutura pessoal:

struct pessoal ptr;

Melhor ainda:

Agente *ptr;

E assim tiras aqueles & antes dos ptrs, que só está lá a acumular lixo.

Faulk_08
11-07-2008, 01:37
Melhor ainda:

Agente *ptr;E assim tiras aqueles & antes dos ptrs, que só está lá a acumular lixo.
Brigado.Resolvi um problema so que agora da-me erro no Nasc


typedef struct {int Dia,Mes,Ano;}Data;
typedef struct pessoal
{
char Nome[100];
char Genero[100];
Data Nascimento;
int Nmc;
int Nmf;
}Agente;
void criar_agente(char nometxt[]){
FILE *file = fopen(nometxt, "ab");
Agente *ptr;
if (file != NULL)
{
printf("Introduza o nome: ");
gets(ptr->Nome);
printf("Introduza o genero: ");
gets(ptr->Genero);
printf("Introduza o dia nascimento: "); scanf("%d", ptr->Nasc.Dia);
printf("Introduza o mes nascimento: "); scanf("%d", ptr->Nasc.Mes);
printf("Introduza o ano nascimento: "); scanf("%d", ptr->Nasc.Ano);
printf("Introduza o numero de missoes concluidas com sucesso: ");
scanf("%d", ptr->Nmc);
printf("Introduza o numero de missoes falhadas: ");
scanf("%d", ptr->Nmf);
fwrite(&ptr, sizeof(Agente), 1, file);
fclose(file);
}
}

O erro é aqui no Nasc
printf("Introduza o dia nascimento: "); scanf("%d", ptr->Nasc.Dia);

AragTey
11-07-2008, 08:32
Brigado.Resolvi um problema so que agora da-me erro no Nasc


Data Nascimento;

printf("Introduza o dia nascimento: "); scanf("%d", ptr->Nasc.Dia);
printf("Introduza o mes nascimento: "); scanf("%d", ptr->Nasc.Mes);
printf("Introduza o ano nascimento: "); scanf("%d", ptr->Nasc.Ano);


O erro é aqui no Nasc

tens declarado Nascimento e não Nasc ;)

Faulk_08
12-07-2008, 16:11
tens declarado Nascimento e não Nasc ;)
Brigadao.Agora ja nao me da erro nenhum mas quando vou a correr sim da-me erro..... :confused:

http://img34.picoodle.com/img/img34/4/7/12/t_blaam_fd5668b.jpg (http://www.picoodle.com/view.php?img=/4/7/12/f_blaam_fd5668b.jpg&srv=img34)