Médio C

Gravando e lendo structs com fwrite/fread

Enunciado

Defina uma struct Pessoa com campos nome (string de até 50 caracteres) e idade (int). Crie um programa que:

  • Abra o arquivo pessoas.bin para escrita binária ("wb").
  • Grave 3 pessoas usando fwrite.
  • Feche o arquivo.
  • Reabra para leitura binária ("rb").
  • Leia e imprima cada pessoa usando fread. Trate erros de abertura e de leitura/escrita.

Requisitos

  • Definir a struct Pessoa corretamente.
  • Usar fopen com modos "wb" e "rb".
  • Usar fwrite para gravar o array de structs de uma vez ou individualmente.
  • Usar fread para ler e verificar se a leitura foi bem-sucedida.
  • Imprimir os dados no formato Nome: <nome>, Idade: <idade>.

Código inicial

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

#define MAX_NOME 50

typedef struct {
    char nome[MAX_NOME];
    int idade;
} Pessoa;

int main(void) {
    // Seu código aqui
    return 0;
}

Saída esperada

Nome: Alice, Idade: 30
Nome: Bob, Idade: 25
Nome: Carol, Idade: 40
Ver dica

Use fwrite(pessoas, sizeof(Pessoa), 3, fp) para gravar o array inteiro. Na leitura, leia uma struct por vez com fread e verifique se retornou 1.

Mostrar solução
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NOME 50

typedef struct {
    char nome[MAX_NOME];
    int idade;
} Pessoa;

int main(void) {
    Pessoa pessoas[3] = {
        {"Alice", 30},
        {"Bob", 25},
        {"Carol", 40}
    };

    // Abre para escrita binária
    FILE *fp = fopen("pessoas.bin", "wb");
    if (fp == NULL) {
        perror("Erro ao abrir para escrita");
        return 1;
    }
    // Grava o array inteiro de uma vez
    size_t escritos = fwrite(pessoas, sizeof(Pessoa), 3, fp);
    if (escritos != 3) {
        fprintf(stderr, "Erro ao gravar: esperado 3, obtido %zu\n", escritos);
        fclose(fp);
        return 1;
    }
    fclose(fp);

    // Abre para leitura binária
    fp = fopen("pessoas.bin", "rb");
    if (fp == NULL) {
        perror("Erro ao abrir para leitura");
        return 1;
    }
    Pessoa p;
    // Lê uma struct por vez até o fim do arquivo
    while (fread(&p, sizeof(Pessoa), 1, fp) == 1) {
        printf("Nome: %s, Idade: %d\n", p.nome, p.idade);
    }
    fclose(fp);
    return 0;
}

Passo a passo

  1. Definimos a struct Pessoa com um array de char para o nome e um int para a idade.
  2. Criamos um array pessoas com 3 elementos já inicializados.
  3. Abrimos o arquivo pessoas.bin no modo "wb" (escrita binária). Verificamos se fopen retornou NULL.
  4. Usamos fwrite para gravar o array inteiro: passamos o endereço do array, o tamanho de cada elemento (sizeof(Pessoa)) e a quantidade (3). O retorno é o número de elementos escritos; deve ser 3.
  5. Fechamos o arquivo.
  6. Reabrimos no modo "rb" (leitura binária) e verificamos erro.
  7. Declaramos uma Pessoa p e usamos fread para ler um elemento por vez. O loop continua enquanto fread retornar 1 (um elemento lido).
  8. Imprimimos os dados e fechamos o arquivo.

Por que funciona

fwrite e fread operam em blocos de bytes, sendo ideais para gravar structs diretamente na memória. O modo "wb" garante que nenhuma tradução de caracteres (como \n para \r\n no Windows) ocorra, preservando a representação binária. Verificar os retornos assegura que a operação foi completa.

Erros comuns

  • Usar modo texto ("w") para dados binários: pode corromper os dados em sistemas que traduzem quebras de linha. Use "wb" e "rb".
  • Esquecer de verificar o retorno de fwrite: se o disco estiver cheio, a gravação pode ser parcial. Compare com o número esperado.
  • Ler com fread sem verificar o retorno: o loop pode tentar processar dados inválidos. Use while (fread(...) == 1).
  • Não fechar o arquivo antes de reabrir: pode causar comportamento indefinido. Sempre fclose.

Outra forma de resolver

Poderia gravar cada struct individualmente com fwrite(&pessoas[i], sizeof(Pessoa), 1, fp) dentro de um loop. A leitura seria similar. A abordagem em bloco é mais eficiente para arrays grandes.

Saída esperada

Nome: Alice, Idade: 30
Nome: Bob, Idade: 25
Nome: Carol, Idade: 40