Ir ao conteúdo
  • Cadastre-se

C ler struct em arquivo binário


Ray fourth

Posts recomendados

estou com duvidas nesse tipo de código até então foi o que fiz, não sei se está certo

 

typedef struct pessoa {

char nome [30];

char cpf [15];

int idade; } pessoa;

 

void ler pessoa(){

file *p;

p = fopen("arquivo.bin", "rb");

if(p==NULL){

printf("erro ao abrir o arquivo.\n");

exit(1);}

 

struct pessoa;

fread(pessoa, sizeof(pessoa), 1, p);

printf("%s\n %s\n %d\n", pessoa.nome, pessoa.cpf, pessoa.idade):

fclose(p);

}

 

é isso? se não for, podem me ajudar no que errei ou algo que posso melhorar?

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Olá. Já começando com a struct:

typedef struct pessoa {
    char nome [30];
    char cpf [15];
    int idade;
} Pessoa;

E para definir um tipo Pessoa:

Pessoa pessoa;

Apenas uma correção no uso do fread:

fread(&pessoa, sizeof(Pessoa), 1, arquivo);

E file seria FILE:

FILE *p

Logo, seu código poderia ficar assim:

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

typedef struct pessoa {
    char nome [30];
    char cpf [15];
    int idade; 
} Pessoa;

void ler_pessoa() {

    FILE *arquivo;
    Pessoa pessoa;

    arquivo = fopen("arquivo.bin", "rb");

    if (arquivo == NULL) {
        printf("erro ao abrir o arquivo.\n");
        exit(1);
    }
    // aqui estou lendo todos os registros existentes no arquivo. Se quer ler 1 só registro 1 fread
    fread(&pessoa, sizeof(Pessoa), 1, arquivo);
    do {
        printf("Nome: %s\nCPF: %s\nIDADE: %d\n", pessoa.nome, pessoa.cpf, pessoa.idade);
        fread(&pessoa, sizeof(Pessoa), 1, arquivo);
    } while (!feof(arquivo)); // enquanto não chegar ao final do arquivo

    fclose(arquivo);
}

int main(void) {

    ler_pessoa();

    return 0;
}

É importante entender bem o que está sendo feito. Se tiver dúvidas é só perguntar!

Obs: Começou a mil com o C né amigo (!?) É por aí!

Link para o comentário
Compartilhar em outros sites

@giu_d a principio eu dei uma moscada na parte do ciclo While mas depois de prestar mais atenção, entendi que o laço continuará sendo executado enquanto tiver conteúdo pra ser exibido (enquanto for diferente de end of file).

 

sua explicação me esclareceu muita coisa, mas ainda não consegui pegar o porque de ter um Fread fora do do e um Fread dentro do do.

 

outra pergunta que tenho é, o printf vem sempre antes do Fread ou tanto faz?

 

 

muito obrigado pela resposta :)

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Olá. Quanto a ter um fread fora do do/while e outro dentro o primeiro faz apenas a leitura de um registro, já depois é feita a leitura dentro de um loop (do / while). Ou seja, enquanto não chegar no final do arquivo leia os registros um a um e imprima.

Quanto a ordem do printf vir antes do fread para entender melhor é só inverter essa ordem, você vai ver q já não vai funcionar do mesmo modo, pois vai ser lida uma estrutura e assim essa última estrutura vai ser impressa duas vezes. Experimenta fazer o teste aí.

Outra forma de ler todos os registros do arquivo seria essa:

while (fread(&pessoa, sizeof(Pessoa), 1, arquivo) == 1)
    printf("NOME: %s\nCPF: %s\nIDADE: %d\n", pessoa.nome, pessoa.cpf, pessoa.idade);

 Devo dizer que ainda não tenho a maturidade necessária para te dar uma explicação melhor para o uso do fread,  mas estou correndo atrás disso

Link para o comentário
Compartilhar em outros sites

@giu_d agora entendi, e se eu quisesse adicionar algo nessa struct, eu teria que criar outra variável? ou poderia armazenar nessa variável pessoa? acredito que na escrita não se usaria o while, ou estou errado?

 

 

desculpe te importunar, é que não achei nada que me explicasse de forma que pudesse entender na intenet.

 

desde já te agradeço por sanar minhas duvidas aqui no fórum

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Olá. Pergunte mesmo, eu costumo fazer muito disso. O q não faço e ver algo e continuar com dúvidas.

Fiz um pequeno exercício q é basicamente o seu código que faz a leitura do arquivo e coloquei a função para gravar no arquivo

Dê uma boa olhada no código e se tiver dúvidas é só perguntar.

Foquei mais na parte didática com esse exercício. Segue o código:

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

typedef struct pessoa {
    char nome [30];
    char cpf [15];
    int idade;
} Pessoa;

void limpa_linha() {
    scanf("%*[^\n]");
    scanf("%*c");
}

void ler_registros() {

    FILE *arquivo;
    Pessoa pessoa;

    arquivo = fopen("arquivo.bin", "rb");

    if (arquivo == NULL) {
        printf("erro ao abrir o arquivo.\n");
        exit(1);
    }

    printf("\n ========== PESSOAS CADASTRADAS ==========\n\n");

    fread(&pessoa, sizeof(Pessoa), 1, arquivo);
    do {
        printf("\nNOME: %s\nCPF: %s\nIDADE: %d\n", pessoa.nome, pessoa.cpf, pessoa.idade);
        fread(&pessoa, sizeof(Pessoa), 1, arquivo);
    } while (!feof(arquivo)); // enquanto não chegar ao final do arquivo

    fclose(arquivo);
}

void gravar_registros() {

    FILE *arq;
    Pessoa pessoa;
    int i, n_reg;

    printf("\nQuantidade de registros para incluir: ");
    scanf("%d", &n_reg);
    limpa_linha();

    arq = fopen("arquivo.bin", "a+b"); // Leitura e escrita, colocando o ponteiro do arquivo no final deste, criando o arquivo caso o mesmo não exista.

    if (arq == NULL) {
        perror("Erro");
        exit(1);
    }
    for (i = 0; i < n_reg; i++) {

        printf("\nDigite o nome da pessoa: ");
        scanf("%[^\n]", pessoa.nome);
        limpa_linha();

        printf("Digite o cpf: ");
        scanf("%s", pessoa.cpf);
        limpa_linha();

        printf("Digite a idade: ");
        scanf("%d", &pessoa.idade);
        limpa_linha();

        fwrite(&pessoa, sizeof(Pessoa), 1, arq);
    }
    fclose(arq);
}

int main(void) {

    char opcao;

    do {
        gravar_registros();

        ler_registros();

        printf("\nDeseja continuar? [s/n]: ");
        scanf("%c", &opcao);
        limpa_linha();

    } while (opcao == 's');

    return 0;
}

Procure ver se deu para entender bem. Se ficar com dúvidas pergunte!

Obs: Estou usando uma função para limpar a sujeira do buffer, a função limpa_linha. Se porventura não entender bem essa função não se preocupe. Eu também demorei p entender, mas mesmo assim usava essa função em meus códigos. Só evite o uso do comando fflush(stdin);. Esse comando é ideal p limpar o stdout, saída padrão. Para o stdin, que referente a entrada padrão (teclado) esse comando tem um comportamento inesperado!

Se quiser inserir mais um dado referente a pessoa, por exemplo o número do título de eleitor, seria isso:

typedef struct pessoa {
    char nome [30];
    char cpf [15];
    char titulo[20];
    int idade;
} Pessoa;

E aí faz a leitura desse valor dessa forma:

printf("Digite o num do titulo de eleitor: ");
scanf("%s", pessoa.titulo);
limpa_linha();

E para ler esse novo dado é só colocar no printf na hora de ler os registros:

printf("\nNOME: %s\nCPF: %s\nIDADE: %d\nNUM TITULO: %s\n", 
    pessoa.nome, pessoa.cpf, pessoa.idade, pessoa.titulo);

Creio q não vai ter dificuldade em entender :thumbsup:

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Olá. Quando você usa o comando typedef o q você está fazendo seria dando um "apelido" para determinado tipo de dado, por exemplo. Também vale para funções e tal.

Veja esse exemplo:

typedef char *string;

typedef enum { FALSE, TRUE } bool;

Nesses primeiro exemplo, toda vez q eu quiser criar um ponteiro do tipo char * ao invés de fazer isso:

char *nome;

Eu posso fazer isso:

string nome;

Que é a mesma coisa. Eu "apelidei" o tipo char * de string

No segundo exemplo, eu posso fazer isso:

while (TRUE) { // enquanto for verdadeiro
    // código
}

No exercício acima o que está sendo feito com o typedef é "apelidando" a estrutura 'struct pessoa' de 'Pessoa'.

Logo, quando você faz isso: Pessoa pessoa, equivale a fazer isso: struct pessoa pessoa. Daria para dar outro nome: Pessoa p (por exemplo) que equivale a isso: struct pessoa p, e aí fazer isso: p.nome (por exemplo). Poderia se o nome q quiser para a struct pessoa, ou Pessoa

Não sei se deu para entender exatamente o q procurei explicar. Só que seria importante entender bem isso.

Outra forma para ficar mais fácil de entender:

struct pessoa {
    char nome [30];
    char cpf [15];
    char titulo[20];
    int idade;
};

typedef struct pessoa Pessoa;

Se você fizer como está nesse último exemplo, vai ver q o código vai funcionar do mesmo modo

Se ainda não ficou claro é só perguntar!

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Vou passar um exemplo mais simples:

typedef int inteiro; // aqui estou "apelidando" o tipo int de inteiro

int main(void) {

    inteiro x = 10; // aqui equivale a isso: int x = 10;

    printf("Valor de x: %d\n", x); // imprime 10

    return 0;
}

É importante saber que eu não estou criando um novo tipo de dado. Apenas o gosto de dizer "apelidando"

Tem sim uma ordem  e é importante seguir essa ordem.

Na sua pergunta está assim:

18 minutos atrás, joao.victork991 disse:

eu apelidei minha struct cadastro de CLIENTE,  poderia ser CLIENTE cadastro

Se você fez isso:

typedef struct cadastro CLIENTE; // aqui você está 'apelidando' a struct cadastro de CLIENTE

// e aí fazer isso:
CLIENTE c;

Já se você fizer isso:

struct cadastro
{
    char nome[50];
} CLIENTE;

// e aí seria isso:
CLIENTE.nome;

Perceba a diferença entre usar o typedef e sem o typedef     

Link para o comentário
Compartilhar em outros sites

Vamos considerar que a struct seria assim:

struct pessoa {
    char nome [30];
    char cpf [15];
    char titulo[20];
    int idade;
};

Perceba agora que não tem o typedef. Então você teria que fazer dessa forma para o código funcionar:

struct pessoa pessoa;

// ou 

struct pessoa p;

E aí no fwrite seria isso:

struct pessoa pessoa;

fwrite(&pessoa, sizeof(struct pessoa), 1, arq);

 

Link para o comentário
Compartilhar em outros sites

16 minutos atrás, giu_d disse:

eu apelidei minha struct cadastro de CLIENTE,  poderia ser CLIENTE cadastro

Poderia. Também poderia ser CLIENTE c ou CLIENTE clientes. Sendo que CLIENTE equivale a struct cadastro definida com o typedef

Dessa forma:

typedef struct cadastro CLIENTE;

Só q fazer algo como CLIENTE cadastro você poderia cair no erro de usar um mesmo nome para duas coisas. No caso o nome "cadastro", que já está sendo usado para o nome da sua struct

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Peraí. Vamos fazer o seguinte. Esqueça por enquanto o uso do typedef.

Logo, vou passar novamente o código que postei acima sem o uso do typedef para você perceber bem a diferença:

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

struct pessoa {
    char nome [30];
    char cpf [15];
    int idade;
};

void limpa_linha() {
    scanf("%*[^\n]");
    scanf("%*c");
}

void ler_registros() {

    FILE *arquivo;
    struct pessoa p; // aqui estou chamando a minha struct pessoa de p, antes era pessoa

    arquivo = fopen("arquivo.bin", "rb");

    if (arquivo == NULL) {
        printf("erro ao abrir o arquivo.\n");
        exit(1);
    }
    printf("\n ========== PESSOAS CADASTRADAS ==========\n\n");

    fread(&p, sizeof(struct pessoa), 1, arquivo);
    do {
        printf("\nNOME: %s\nCPF: %s\nIDADE: %d\n",
               p.nome, p.cpf, p.idade);
        fread(&p, sizeof(struct pessoa), 1, arquivo);
    } while (!feof(arquivo));

    fclose(arquivo);
}

void gravar_registros() {

    FILE *arq;
    struct pessoa pessoa;
    int i, n_reg;

    printf("\nQuantidade de registros para incluir: ");
    scanf("%d", &n_reg);
    limpa_linha();

    arq = fopen("arquivo.bin", "ab"); // abre arquivo para gravação no final do arquivo

    if (arq == NULL) {
        perror("Erro");
        exit(1);
    }

    for (i = 0; i < n_reg; i++) {

        printf("\nDigite o nome da pessoa: ");
        scanf("%[^\n]", pessoa.nome);
        limpa_linha();

        printf("Digite o cpf: ");
        scanf("%s", pessoa.cpf);
        limpa_linha();

        printf("Digite a idade: ");
        scanf("%d", &pessoa.idade);
        limpa_linha();

        fwrite(&pessoa, sizeof(struct pessoa), 1, arq);
    }

    fclose(arq);
}

int main(void) {

    char opcao;

    do {
        gravar_registros();

        ler_registros();

        printf("\nDeseja continuar? [s/n]: ");
        scanf("%c", &opcao);
        limpa_linha();

    } while (opcao == 's');

    return 0;
}

Procure analisar bem a diferença no código. Perceba que na função para ler os registros eu resolvi mudar para 

struct pessoa p. Nesse caso foi preciso mudar na função fread e no printf. Por exemplo: p.nome  etc...

Eu recomendo primeiro aprender a trabalhar com structs sem o uso do typedef. Inclusive eu mesmo demorei para começar a fazer isso. Eu criava meus códigos do modo como passei o código agora

Esse código agora não tem nada de typedef e creio que para começar a mexer com struct seria a melhor maneira, té para evitar fazer confusão

Consegue ver a diferença agora na função fread e fwrite? Agora é sizeof(struct pessoa)

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Devo ser sincero e dizer que seria assim:

CLIENTE c; // aqui é o mesmo que struct cadastro c
fwrite(&c, sizeof(CLIENTE), 1, arq);

ou assim:

struct cadastro c;
fwrite(&c, sizeof(struct cadastro), 1, arq);

Mas não se preocupe caso ainda ficou dúvidas. Cara, você tá indo muito bem em C

Nesse código está sendo trabalhado com struct e leitura e gravação de arquivos binários. Não é algo tão simples assim. 

É passo a passo, degrau por degrau. 

No caso desse exercício você está gravando e lendo uma estrutura toda, é por isso o sizeof(struct pessoa)

Você poderia estar gravando uma palavra de cada vez (por exemplo), mas está sendo trabalhado com uma estrutura toda ao mesmo tempo. Então se tiver dúvidas ainda pode ficar tranquilo porque isso é normal. Eu mesmo já passei e passo por isso no meu dia-a-dia

O segredo mesmo é praticar! Praticar muito mesmo!

Eu normalmente passo algumas horas todo dia criando exercícios e mais exercícios, mas assim eu sei que estou aprendendo

adicionado 7 minutos depois

@joao.victork991 Cara. té há poucos dias você tava encontrando dificuldade para criar um código onde lia algumas notas e imprimia a média dessas notas. Agora você já está trabalhando com exercícios como esse. 

É mais do que normal encontrar uma certa dificuldade e ainda ficar em dúvidas sobre algum ponto.

Mas recomendo, a princípio, fazer até como eu fiz ao trabalhar com struct: Sem o uso do typedef

Só que se você conseguir perceber a diferença nos dois códigos e ficar mais "amadurecido" quanto a gravação de estruturas em arquivos binários, aí sim arrisque usar o typedef para ver se conseguiu entender

Link para o comentário
Compartilhar em outros sites

@joao.victork991 Valeu! Pratique mesmo. Tente refazer sozinho esse exercício q passei. Se achar q consegue, aí arrisque usar um typedef aí no código. Vai tentando, arriscando mesmo, nem q não dê certo após várias tentativas. Mas é assim q se aprende! 

Só vou sair q tenho q acordar cedo amanhã.

Valeu cara! Continue com essa disposição e vontade de aprender pois assim você vai longe!

Abração!

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...