Ir ao conteúdo
  • Cadastre-se

C Leitura e impressão de arquivo com struct em c


ningumx

Posts recomendados

Fiz um código para ler um arquivo, no qual contém o id e o nome de 24 alunos. o que está dando errado é que na hora de consultar e aparecer o relatório, a parte dos dados fica vazio. Creio que tenha feito a leitura errada. Alguém poderia me ajudar?

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

// STRUCT DO ALUNO
typedef struct aluno {
  int id_aluno;
  char nm_aluno[50];
} arq_aluno;

// VARIÁVEIS GLOBAIS
int quant_alunos = 0;
arq_aluno arq_alunos[24];
int escolha;

// FUNÇÃO CONSULTA POR ID
void consulta() {
  FILE *entrada = fopen("alunos.txt", "r");
  int id;

  if(entrada == NULL) {
    printf("Erro na leitura do arquivo...\n");
  } else {
    printf("\n------BUSCA DE ALUNOS------\n");
    printf("Digite o id do aluno: ");
    scanf("%i", &id);
    getchar();

    for (int i = 1; i <= quant_alunos; i++) {
      if (id == arq_alunos[i].id_aluno) {
        printf("Aluno: %s\n", arq_alunos[i].nm_aluno);
      } else if (id != arq_alunos[i].id_aluno)
        printf("Aluno não existe na base!\n");
    }
    printf("---------------------------\n");
  }
  fclose(entrada);
}

// FUNÇÃO RELATÓRIO
void relatorio() {
  FILE *entrada = fopen("alunos.txt", "r");

  for (int i = 1; i <= 24; i++) {
    fscanf(entrada, "%d", &arq_alunos[i].id_aluno);
    fscanf(entrada, "%s", &arq_alunos[i].nm_aluno[50]);
  }

  if (entrada == NULL) {
    printf("Erro na leitura do arquivo...\n");
  } else {
    struct tm *data_hora_atual;
    time_t segundos;
    time(&segundos);
    data_hora_atual = localtime(&segundos);
    int i;

    printf("_____________________________\n");
    printf("\n");
    printf("----RELATÓRIO DE ALUNOS----\n");
    printf("___________________________\n");
    printf("---------------------------\n");
    printf("|   ID   |      NOME      |\n");

    for (int i = 1; i <= quant_alunos; i++) {
      printf("|   %d\t |", arq_alunos[i].id_aluno);
      printf("     %s\t  |", arq_alunos[i].nm_aluno);
    }

    printf("\n-----------------------------\n");
    printf("_______________________________ Gerado em %d/%d/%d %i:%i:%i\n",
           data_hora_atual->tm_mday, data_hora_atual->tm_mon + 1,
           data_hora_atual->tm_year + 1900, data_hora_atual->tm_hour,
           data_hora_atual->tm_min, data_hora_atual->tm_sec);
  }

  fclose(entrada);
}

int main() {
  do {
    setlocale(LC_ALL, "");
    struct tm *data_hora_atual;
    time_t segundos;
    time(&segundos);
    data_hora_atual = localtime(&segundos);
    printf("Acesso em %d/%d/%d %i:%i:%i\n", data_hora_atual->tm_mday,
           data_hora_atual->tm_mon + 1, data_hora_atual->tm_year + 1900,
           data_hora_atual->tm_hour, data_hora_atual->tm_min,
           data_hora_atual->tm_sec);

    printf("--MENU PRINCIPAL--\n");
    printf("------------------\n");
    printf("| [1] - Consultar por id |\n| [2] - Relatório        |\n| [3] - "
           "Sair             |\n");
    printf("------------------\n");
    printf("Opção: ");
    scanf("%d", &escolha);

    switch (escolha) {
    case 1:
      consulta();
      break;
    case 2:
      relatorio();
      break;
    }
  } while (escolha != 3);
  return 0;
}

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@ningumx    nessa linha aqui você colocou a posição 50 da string 

for (int i = 1; i <= 24; i++) 
{
  fscanf(entrada, "%d", &arq_alunos[i].id_aluno);
  fscanf(entrada, "%s", &arq_alunos[i].nm_aluno[50]); /// não precisa informar a posiCAo
}

 e o vetor começa em zero e vai ate 23 ,  assim não precisa colocar o sinal de igual 

for ( int i=0; i<24; i++ ) 

 

você já inseriu alguma coisa nesse arquivo ?

Link para o comentário
Compartilhar em outros sites

3 minutos atrás, devair1010 disse:

@ningumx    nessa linha aqui você colocou a posição 50 da string 

for (int i = 1; i <= 24; i++) 
{
  fscanf(entrada, "%d", &arq_alunos[i].id_aluno);
  fscanf(entrada, "%s", &arq_alunos[i].nm_aluno[50]); /// não precisa informar a posiCAo
}

 e você já inseriu alguma coisa nesse arquivo ?

sim, o arquivo já está completo.

eu inseri o "[50]" depois porque aparecia isto: format specifies type 'char *' but the argument has type 'char (*)[50]'

  • Amei 1
Link para o comentário
Compartilhar em outros sites

Seu programa tem muitos dos problemas comuns que são vistos aqui. Vai ter muito mais trabalho em concluir o programa assim, e vai levar pouco dele para os próximos programas...

 

Sobre esse trecho por exemplo

 

// STRUCT DO ALUNO
typedef struct aluno {
  int id_aluno;
  char nm_aluno[50];
} arq_aluno;

// VARIÁVEIS GLOBAIS
int quant_alunos = 0;
arq_aluno arq_alunos[24];
int escolha;

 

  • Talvez possa evitar esses comentários óbvios e comentar o que está fazendo e porque. Dá pra imaginar por exemplo que struct aluno seja STRUCT DO ALUNO mesmo que você não comente isso.
  • Variáveis declaradas fora do escopo de funções são globais ao arquivo. Não devia usar isso, e nem comentar.
  • Essa struct devia ser anônima. Para que DOIS nomes?
  • Seu programa gira em torno de um cadastro de alunos. Só que não tem essa estrutura no programa. Claro que devia ter. Composição de dados tornaria seu programa muito mais simples e seguro.
  • arq_alunos sugere que seja um arquivo de alunos, só que não é. E dois nomes diferindo por singular e plural por uma coisa que sequer é um arquivo e com um nome que começa por arq só gera confusão

Sobre o programa

 

Se você tem um arquivo de alunos leia e grave alunos e não texto. Só vai trabalhar muito mais. Use o arquivo como o que ele é: uma série de alunos e não uma série de linhas de tamanho variável.

 

Não escreva um programa interativo. Nunca.

Não use globais. Nunca. É proibido em toda parte.

Não use void f(void). É um desastre e só trazer dificuldades

Não use uma série de printf() de uma linha. Use um printf() de uma série de linhas. É dezenas de vezes mais rápido e mais esperto

Não declare variáveis dentro de um else. É pedir por problemas.

TESTE o retorno de scanf(). É ingênuo simplesmente seguir adiante

 

 

 

 

 

  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

@ningumx     e mesmo colocando a quantidade de alunos em 24 não funcionou ,    e deletando aquele loop for , e escrevi ele novamente , aí funcionou ,  

#define     WIN32_WINNT 0x600
#include    <stdio.h>
#include    <conio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <windows.h>
#define     _h GetStdHandle(STD_OUTPUT_HANDLE)
#include <locale.h>
#include <time.h>

typedef struct
{
  int  id_aluno    ;
  char nm_aluno[50];
} arq_aluno        ;

void consulta( arq_aluno Alunos[] , int quant_alunos )
{
  FILE *entrada = fopen("alunos.txt", "r");
  int id;
  if( entrada == NULL )
  {
    printf( "Erro na leitura do arquivo ,. . . !\n");
    return;
  }
    printf("\n------BUSCA DE ALUNOS------\n");
    printf("Digite o id do aluno: ");
    scanf("%i", &id);
    getchar();

    for (int i = 1; i <= quant_alunos; i++)
    {
      if (id == Alunos[i].id_aluno)
      {
        printf("Aluno: %s\n", Alunos[i].nm_aluno);
      }
      else if (id != Alunos[i].id_aluno)
        printf("Aluno não existe na base!\n");
    }
    printf("---------------------------\n");
  fclose(entrada);
}

void relatorio( arq_aluno Alunos[] , int quant_alunos )
{
  FILE* entrada = fopen("alunos.txt", "r");
  if( entrada == NULL )
  {
    printf( "Erro na leitura do arquivo ,. . . !\n");
    return;
  }
  int i;
  printf("_____________________________\n\n"
         " ----RELATÓRIO DE ALUNOS----   \n"
         "___________________________    \n"
         "---------------------------    \n"
         "|   ID   |      NOME      |    \n");
  SetConsoleTextAttribute( _h , 11 + ( 0 << 4 ) );
  for ( int i=0; i<24; i++ )
  {
    fscanf(entrada, "%d", &Alunos[i].id_aluno );
    fscanf(entrada, "%s", &Alunos[i].nm_aluno );
    printf("  %3d    |   %s\n", Alunos[i].id_aluno,
           Alunos[i].nm_aluno);
  }
  struct tm *data_hora_atual;
  time_t segundos;
  time(&segundos);
  data_hora_atual = localtime(&segundos);
  printf("-----------------------------\n\n");
  printf
  (
    "_______________________________\n\n"
    " Gerado em %d/%d/%d %i:%i:%i"      ,
    data_hora_atual->tm_mday            , 
    data_hora_atual->tm_mon  + 1        ,
    data_hora_atual->tm_year + 1900     , 
    data_hora_atual->tm_hour            ,
    data_hora_atual->tm_min             , 
    data_hora_atual->tm_sec
  );
  fclose(entrada);
}

int main()
{
  FILE* arq;
  int quant_alunos = 24 ;
  arq_aluno Alunos  [24];
  int cor_letra, cor_fundo;
  CONSOLE_SCREEN_BUFFER_INFO c;
  if( GetConsoleScreenBufferInfo( _h, & c )      )
  {
    cor_letra = (  c.wAttributes & 0xFF  )        & 0x0F;
    cor_fundo = ( (c.wAttributes & 0xFF  ) >> 4 ) & 0x0F;
  }
  int escolha;
  arq = fopen("alunos.txt","a"); /// abre para ler ou gravar a partir o final do arquivo
  fprintf(arq,"%s","5 kiko\n");  /// id antes e nome depois
  fclose( arq );
  do
  {
    setlocale(LC_ALL, "");
    struct tm *data_hora_atual;
    time_t segundos;
    time(&segundos);
    data_hora_atual = localtime(&segundos);
    printf("\nAcesso em %d/%d/%d %i:%i:%i\n\n", data_hora_atual->tm_mday,
    printf
    (
      "\nAcesso em %d/%d/%d %i:%i:%i\n\n",
      data_hora_atual->tm_mday           ,
      data_hora_atual->tm_mon  + 1       , 
      data_hora_atual->tm_year + 1900    ,
      data_hora_atual->tm_hour           , 
      data_hora_atual->tm_min            ,
      data_hora_atual->tm_sec
    );
    SetConsoleTextAttribute( _h , 14 + ( 0 << 4 ) );
    printf("   --MENU PRINCIPAL--\n");
    printf("|------------------------|\n");
    printf("| [1] - Consultar por id |\n"
           "| [2] - Relatório        |\n"
           "| [3] - Sair             |\n"
           "-------------------------|\n"
           "        Opção: "           );
    scanf("%d", &escolha);
    switch (escolha)
    {
    case 1:
      consulta( Alunos , quant_alunos );
      break;
    case 2:
      relatorio( Alunos , quant_alunos );
      break;
    case 3:
      SetConsoleTextAttribute( _h , 12 + ( 15 << 4 ) );
      printf("   Saindo do Programa . . . !\n\n\n");
      SetConsoleTextAttribute( _h , cor_letra + ( cor_fundo << 4 ) );
    }
  }
  while ( escolha != 3 );
  return 0;
}

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Em 09/12/2022 às 14:17, ningumx disse:

Fiz um código para ler um arquivo, no qual contém o id e o nome de 24 alunos. o que está dando errado é que na hora de consultar e aparecer o relatório, a parte dos dados fica vazio. Creio que tenha feito a leitura errada

 

Se quer ler um arquivo comece por CRIAR o arquivo. E não escreva um monte de código antes de testar. E, como eu disse, nunca escreva um programa interativo. Só vai perder muito tempo. E nunca misture a lógica com entrada e saída, como fez em consulta().

 

Isso

 

        void consulta( arq_aluno Alunos[] , int quant_alunos );

 

Não é conveniente.

 

Na verdade o que você quer é algo assim

 

	int consulta( int id, arq_aluno Alunos[] , int quant_alunos );

 

Se você encontrar o aluno com a id procurada retorna a posição dele no vetor. Se não achar retorna -1. Muito mais simples.

 

Escreva em torno dos dados

 

typedef struct
{
    int  id;
    char nome[50];
}   Aluno;

 

Essa é a unidade de dado para o programa. Note que raramente vai ter sentido um id negativo, e raramente um tamanho fixo para o nome vai servir. Então o normal seria algo assim

 

typedef struct
{
    unsigned  id;
    char* nome;
}   Aluno;

 

E resista a usar coisas como fez:
 

// STRUCT DO ALUNO
typedef struct aluno
{
    int  id_aluno;
    char nm_aluno[50];
} arq_aluno;

 

Não há razão para dois nomes. E não há razão para repetir aluno toda hora já que os dois campos estão afinal dentro de Aluno.

 

Reservar a primeira letra em maiúscula para nomes que você define é uma convenção, e deve usar algo assim.

 

Uma alternativa

 

Escrevendo em torno dos dados programas simples e rápidos é o caminho para testar logo, em minutos. E não voltar atrás.
 

Aluno* al_cria()
{
    static int id  = 1; // id do novo aluno
    Aluno* novo = (Aluno*)malloc(sizeof(Aluno));
    if (novo == NULL) return NULL;
    novo->id = id;
    sprintf(novo->nome, "Aluno %06d", id);
    id += 1;
    return novo;
}

 

Essa função retorna um aluno novo a cada vez que você chama. Bem melhor que ficar digitando e inventando dados a cada teste. e tem SETE linhas. Os Aluno tem id a partir de 1 e nome "Aluno 000001" e serve bem para centenas de milhares de alunos.

 

int al_mostra(Aluno* al)
{
    if (al == NULL) return -1;
    printf("id=%6d, nome=\"%s\"\n", al->id, al->nome);
    return 0;
}

 

Essa função mostra um Aluno numa linha. E tem só TRES linhas.

 

Então esse programa de SETE linhas

 

int main(void)
{
    Aluno* al = NULL;
    for (int i = 0; i < 24; i += 1) { 
        al = al_cria();
        al_mostra(al);
        free(al);
    }
    return 0;
}

 

mostra na tela

 

id=     1, nome="Aluno 000001"
id=     2, nome="Aluno 000002"

// ...

id=    24, nome="Aluno 000024"

 

E já é um começo, em 5 minutos.

 

Primeiro teste, em minutos

 

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

typedef struct
{
    int  id;
    char nome[50];
}   Aluno;

Aluno* al_cria();
int    al_mostra(Aluno*);


int main(void)
{
    Aluno* al = NULL;
    for (int i = 0; i < 24; i += 1)
    { 
        al = al_cria();
        al_mostra(al);
        free(al);
    }
    return 0;
}

Aluno* al_cria()
{
    static int id  = 1; // id do novo aluno
    Aluno* novo = (Aluno*)malloc(sizeof(Aluno));
    if (novo == NULL) return NULL;
    novo->id = id;
    sprintf(novo->nome, "Aluno %06d", id);
    id += 1;
    return novo;
}

int al_mostra(Aluno* al)
{
    if (al == NULL) return -1;
    printf("id=%6d, nome=\"%s\"\n", al->id, al->nome);
    return 0;
}

 

E assim tem os dados para por no arquivo

 

Um segundo programa

 

int main(void)
{
    Aluno* al = NULL;
    const char* arquivo = "exemplo.aln";
    FILE*       out     = fopen(arquivo, "wb");
    if (out == NULL) return -1; // ja era deu erro
    printf(
        "Tamanho do registro de Aluno = %llu\n\n",
        sizeof(Aluno));
    for (int i = 0; i < 24; i += 1)
    {
        al = al_cria();
        al_mostra(al);
        size_t res = fwrite(al, sizeof(Aluno), 1, out);
        free(al); // libera: não vai usar mais
        if (res != 1)
        {   // deu erro ao gravar um aluno
            printf(
                "Erro ao tentar gravar aluno com id=%d\n",
                al->id);
            break;
        }
    }
    fclose(out);
    return 0;
}

 

Então esse programa grava os registros todos no arquivo... Foi só isso que mudou. Então se der erro só pode ser aí.

 

Eis a saída

 

Tamanho do registro de Aluno = 56

id=     1, nome="Aluno 000001"
id=     2, nome="Aluno 000002"
// ...
id=    23, nome="Aluno 000023"
id=    24, nome="Aluno 000024"

 

Agora sim podemos tentar ler isso... A gente sabe que os dados estão certos, vimos na tela. A gente sabe que gravou certo porque não saiu mensagem de erro.

 

Então se pode tentar ler isso num terceiro programa:

 

int main(void)
{
    Aluno       al      = {0};
    const char* arquivo = "exemplo.aln";
    FILE*       in      = fopen(arquivo, "rb");
    if (in == NULL) return -1;  // ja era deu erro
    size_t res = 1;
    size_t N   = 0;
    while ( 1 == (res = fread(&al, sizeof(Aluno), 1, in)) )
    {
        N += 1;
        al_mostra(&al);
    }
    printf("\n\t==> Lidos %llu alunos\n", N);
    fclose(in);
    return 0;
}

 

E se ele ler os 24 está tudo certo. 

 

Eis a saída

 

id=     1, nome="Aluno 000001"
id=     2, nome="Aluno 000002"
id=     3, nome="Aluno 000003"
id=     4, nome="Aluno 000004"
id=     5, nome="Aluno 000005"
id=     6, nome="Aluno 000006"
id=     7, nome="Aluno 000007"
id=     8, nome="Aluno 000008"
id=     9, nome="Aluno 000009"
id=    10, nome="Aluno 000010"
id=    11, nome="Aluno 000011"
id=    12, nome="Aluno 000012"
id=    13, nome="Aluno 000013"
id=    14, nome="Aluno 000014"
id=    15, nome="Aluno 000015"
id=    16, nome="Aluno 000016"
id=    17, nome="Aluno 000017"
id=    18, nome="Aluno 000018"
id=    19, nome="Aluno 000019"
id=    20, nome="Aluno 000020"
id=    21, nome="Aluno 000021"
id=    22, nome="Aluno 000022"
id=    23, nome="Aluno 000023"
id=    24, nome="Aluno 000024"

        ==> Lidos 24 alunos

 

E não é que leu?  

 

15 minutos, 3 programas simples, um editado do outro.

 

Agora sabendo que leu fica fácil pensar no resto...

 

Sem globais, sem interatividade, sem sustos.

 

  • Obrigado 2
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...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!