Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

netinhocqc

realloc

Mensagens Recomendadas

netinhocqc

Ola, boa tarde estou com dois problemas no seguinte código. o primeiro não consigo fazer um realloc na função preencher e o segundo não consigo lê os dados no arquivo na função imprimir. Desde já agradeço.

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

typedef struct cadastro{
        char nome[30];
        int idade;
        int matricula;
}cadastro;

void preencher(cadastro *aluno, int cont);
void imprimir(cadastro *aluno);
void pesquisar(cadastro *aluno);
void criar();

int main(){
    int op;
    FILE *arquivo;
    int cont=0;
    cadastro *aluno;
    aluno = (cadastro *)malloc(sizeof(cadastro)*cont);
    criar();
    printf("\t\t\t\tCadastro de Alunos\n\n");
    do{
       printf("--------------------------------------------------------------------------------\n\n");
       printf("\t\t\t\t(1) - Cadastrar Aluno \n");
       printf("\t\t\t\t(2) - Lista Alunos \n"); 
       printf("\t\t\t\t(3) - Pesquisar Aluno \n");
       printf("\t\t\t\t(4) - Ordenar Lista\n");
       printf("\t\t\t\t(5) - Remover Alunos\n");
       printf("\t\t\t\t(6) - Sair\n\n");
       printf("--------------------------------------------------------------------------------\n\n");
       printf("Digite sua opcao: ");
       scanf("%d",&op);
       switch(op){
              case 1:
                   cont++;
                   preencher(aluno, cont); 
                   break;
              case 2:
                   imprimir(aluno);
                   break;
              case 3:
                   pesquisar(aluno);
                   break;          
              default:
                   printf("Saindo!\n");
       }                              
    }while(op != 6);
    system("pause");
}     
void criar(){
      FILE *arquivo;
      if((arquivo = fopen("Windows.txt","wb")) == NULL){
         exit(0);
     }
     fclose(arquivo);
}
void pesquisar(cadastro *aluno){
     FILE *arquivo;
     char Npesquisa[50];
     fflush(stdin);
     if((arquivo = fopen("Windows.txt","rb")) == NULL){
         exit(0);
     }
      printf("--------------------------------------------------------------------------------\n\n");
     printf("Digite do Aluno que deseja pesquisar: ");
     fgets(Npesquisa,50,stdin); 
     printf("\n");      
     if(fread(&aluno,sizeof(struct cadastro),1,arquivo) != 1){
         exit(0);
         }
     if(strcmp(Npesquisa,aluno->nome) == 0){
        fread(&aluno,sizeof(struct cadastro),1,arquivo);                         
        printf("Nome: %sIdade: %d\nMatricula %d\n",aluno->nome, aluno->idade, aluno->matricula);
     }else{
        printf("Nome nao encontrado\n");
     } 
     fclose(arquivo);    
     printf("--------------------------------------------------------------------------------\n\n");
}        


void imprimir(cadastro *aluno){
      FILE *arquivo;
      if((arquivo = fopen("Windows.txt","rb")) == NULL){
         exit(0);
     }
     
     while(fread(&aluno,sizeof(struct cadastro),1,arquivo)! EOF){
        fread(&aluno,sizeof(struct cadastro),1,arquivo);                   
        printf("Nome: %sIdade: %d\nMatricula %d\n",aluno->nome, aluno->idade, aluno->matricula);
     }
     fclose(arquivo); 
} 
     
void preencher(cadastro *aluno, int cont){
     FILE *arquivo;
     if((aluno = (cadastro *)realloc(aluno,cont*sizeof(cadastro))) == NULL){
        exit(0);
     }
     if((arquivo = fopen("Windows.txt","wb")) == NULL){
        exit(0);
     }
     for(int i=0; i<cont; i++){
        fflush(stdin);
        printf("Digite o Nome do Aluno: ");
        fgets(aluno->nome,30,stdin);
        printf("Digite a Idade do Aluno: ");
        scanf("%d",&aluno->idade);
        printf("Digite a Matricula do Aluno: ");
        scanf("%d",&aluno->matricula);
        fwrite(&aluno,sizeof(struct cadastro),1,arquivo);
     }
     fclose(arquivo);
}    


Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

1) Tens que passar um ponteiro para o ponteiro:

void preencher(cadastro **aluno, int cont);

2) Tens dois fread seguidinhos; um dentro da condicao do while, outro dentro do loop. Um chega. fread nunca devolve EOF!

while (1) {
    if (fread(&aluno, sizeof (struct cadastro), 1, arquivo) < 1) break;
    /* ... usa dados ... */
}


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
netinhocqc

Sei mais a função agora esta apresentando um erro, dizendo  `idade' has not been declared. também está dando um erro em cima da linha realloc.

void preencher(cadastro **aluno, int cont){
     FILE *arquivo;
     if(aluno = (cadastro *)realloc(aluno,cont*sizeof(cadastro)) == NULL){
        exit(0);
     }
     if((arquivo = fopen("Windows.txt","ab")) == NULL){
        exit(0);
     }
     for(int i=0; i<cont; i++){
        fflush(stdin);
        printf("Digite o Nome do Aluno: ");
        fgets(aluno->nome,30,stdin);
        printf("Digite a Idade do Aluno: ");
        scanf("%d",&aluno->idade);
        printf("Digite a Matricula do Aluno: ");
        scanf("%d",&aluno->matricula);
        fwrite(&aluno,sizeof(struct cadastro),1,arquivo);
     }
     fclose(arquivo);
}     


Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Dentro da funcao, a variavel aluno nao é de tipo ponteiro para cadastro: é do tipo ponteiro para ponteiro para cadastro.

Para "desreferenciares" o primeiro nivel usa parentesis:

&(*aluno)->idade

Tens que fazer alteracoes parecidas na funcao toda!

Sugestao: aumentao nivel de warnings do teu compilador para o maximo que conseguires. Talvez ele te avise das tentativas erradas que fizeres.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
netinhocqc

Fiz as alterações que você disse mais agora continua um erro com realloc e agora apareceu um erro ao listar na função imprimir



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

typedef struct cadastro{
        char nome[30];
        int idade;
        int matricula;
}cadastro;

void preencher(cadastro **aluno, int cont);
void imprimir(cadastro **aluno);
void pesquisar(cadastro **aluno);
void criar();

int main(){
    int op;
    FILE *arquivo;
    int cont=0;
    cadastro **aluno;
    aluno = (cadastro **)malloc(cont*sizeof(cadastro*));
    criar();
    printf("\t\t\t\tCadastro de Alunos\n\n");
    do{
       printf("--------------------------------------------------------------------------------\n\n");
       printf("\t\t\t\t(1) - Cadastrar Aluno \n");
       printf("\t\t\t\t(2) - Lista Alunos \n"); 
       printf("\t\t\t\t(3) - Pesquisar Aluno \n");
       printf("\t\t\t\t(4) - Ordenar Lista\n");
       printf("\t\t\t\t(5) - Remover Alunos\n");
       printf("\t\t\t\t(6) - Sair\n\n");
       printf("--------------------------------------------------------------------------------\n\n");
       printf("Digite sua opcao: ");
       scanf("%d",&op);
       switch(op){
              case 1:
                   cont++;
                   preencher(aluno, cont); 
                   break;
              case 2:
                   imprimir(aluno);
                   break;
              case 3:
                  pesquisar(aluno);
                   break;          
              default:
                   printf("Saindo!\n");
       }                              
    }while(op != 6);
    system("pause");
}     
void criar(){
      FILE *arquivo;
      if((arquivo = fopen("Windows.txt","wb")) == NULL){
         exit(0);
     }
     fclose(arquivo);
}
void pesquisar(cadastro **aluno){
     FILE *arquivo;
     char Npesquisa[50];
     fflush(stdin);
     if((arquivo = fopen("Windows.txt","rb")) == NULL){
         exit(0);
     }
      printf("--------------------------------------------------------------------------------\n\n");
     printf("Digite do Aluno que deseja pesquisar: ");
     fgets(Npesquisa,50,stdin); 
     printf("\n");      
     if(fread(&aluno,sizeof(struct cadastro),1,arquivo) != 1){
         exit(0);
         }
     if(strcmp(Npesquisa,(*aluno)->nome) == 0){
        fread(&aluno,sizeof(struct cadastro),1,arquivo);                         
        printf("Nome: %sIdade: %d\nMatricula %d\n",(*aluno)->nome, (*aluno)->idade, (*aluno)->matricula);
     }else{
        printf("Nome nao encontrado\n");
     } 
     fclose(arquivo);    
     printf("--------------------------------------------------------------------------------\n\n");
}        


void imprimir(cadastro **aluno){
      FILE *arquivo;
      if((arquivo = fopen("Windows.txt","rb")) == NULL){
         exit(0);
     }
     while (1) {
    if (fread(&aluno, sizeof (struct cadastro), 1, arquivo) < 1){ 
        break;
    }
    printf("Nome: %sIdade: %d\nMatricula %d\n",(*aluno)->nome, (*aluno)->idade, (*aluno)->matricula);
     }
     fclose(arquivo); 
} 
     
void preencher(cadastro **aluno, int cont){
     FILE *arquivo;
     if(aluno = (cadastro **)realloc(aluno,sizeof(cadastro*)*cont) == NULL){
        exit(0);
     }
     if((arquivo = fopen("Windows.txt","ab")) == NULL){
        exit(0);
     }
     for(int i=0; i<cont; i++){
        fflush(stdin);
        printf("Digite o Nome do Aluno: ");
        fgets((*aluno)->nome,30,stdin);
        printf("Digite a Idade do Aluno: ");
        scanf("%d",&(*aluno)->idade);
        printf("Digite a Matricula do Aluno: ");
        scanf("%d",&(*aluno)->matricula);
        fwrite(&aluno,sizeof(struct cadastro),1,arquivo);
     }
     fclose(arquivo);
}     

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Agora tens um nivel de indireccao a mais na definicao (dentro da funcao main) da variavel aluno.

Dentro da funcao main, a variavel nao deve ser ponteiro para ponteiro, mas simplesmente um ponteiro.

Da mesma forma que funcionas com variaves inteiras funcionas com ponteiros.

Supoe que tens uma variavel k e que a queres passar para uma funcao e que esta funcao a altere. Defines a variavel normalmente; passas o endereco para a funcao, certo?

void alterak(int *k);
int main(void) {
    int k;
    alterak(&k);
    return 0;
}

Dentro da funcao main, o k é um inteiro; dentro da funcao alterak, ele é um ponteiro para um inteiro.

Este programa tem 2 ks diferentes. A unica relacao entre eles e mantida pelas funcoes chamadas dentro de main.

Com ponteiros é absolutamente igual: defines a variavel normalmente; passas o endereco para a funcao

void preencher(cadastro **aluno, int cont);
int main(void) {
    cadastro *aluno;
    aluno = malloc(sizeof *aluno);
    if (aluno == NULL) exit(EXIT_FAILURE);
    preencher(&aluno, 42);
    free(aluno);
    return 0;
}

Dentro da funcao main, o aluno é um ponteiro para cadastro; dentro da funcao preencher, ele é um ponteiro para um ponteiro para cadastro.

Este programa tem 2 alunos diferentes. A unica relacao entre eles e mantida pelas funcoes chamadas dentro de main.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
netinhocqc

Blz estou entendendo fiz as alterações mais agora não esta mais gravando no arquivo

void preencher(cadastro **aluno, int cont){
     FILE *arquivo;
     if(aluno = (cadastro **)realloc(aluno,sizeof(cadastro*)*cont) == NULL){
        exit(0);
     }
     if((arquivo = fopen("Windows.txt","ab")) == NULL){
        exit(0);
     }
     for(int i=0; i<cont; i++){
        fflush(stdin);
        printf("Digite o Nome do Aluno: ");
        fgets((*aluno)->nome,30,stdin);
        printf("Digite a Idade do Aluno: ");
        scanf("%d",&(*aluno)->idade);
        printf("Digite a Matricula do Aluno: ");
        scanf("%d",&(*aluno)->matricula);
        fwrite(&aluno,sizeof(struct cadastro**),1,arquivo);
     }
     fclose(arquivo);
} 




Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pmg

Se aluno é um ponteiro para ponteiro para cadastro (como esta na definicao da funcao preencher), o que achas que é um

&aluno

???

Eu digo-te ... é um ponteiro para um ponteiro para um ponteiro para cadastro.

Nao é isso que queres usar no fwrite.


What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mundo

Não estás realmente a abrir o ficheiro acho, estás a dizer muito bem que se o fopen for igual a NULL que sai, mas não tens o ficheiro aberto propriamente dito, penso eu, ainda sou um pouco verde na parte que toca a ficheiros, e ainda estou a aprender, se disse algo mal peço que me corrijam xD

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

O problema não está na abertura do ficheiro. Isso está correcto.

Como o pmg disse, o problema está na manipulação dos apontadores.

Não é fácil acertar com a aritmética necessária nestes casos, mas tu estás com grandes falhas. Posto uma solução logo que possa, até lá aconselho-te a estudar apontadores.

void preencher(cadastro **aluno, int cont){
     FILE *arquivo;
     int i=0;
     if((*aluno = (cadastro *)realloc(*aluno,sizeof(cadastro)*cont)) == NULL){
        exit(0);
     }
     if((arquivo = fopen("Windows.txt","ab")) == NULL){
        exit(0);
     }
     for(i=0; i<cont; i++){
        fflush(stdin);
        printf("Digite o Nome do Aluno: ");
        fgets((*aluno)[i].nome,30,stdin);
        printf("Digite a Idade do Aluno: ");
        scanf("%d",&((*aluno)[i].idade));
        printf("Digite a Matricula do Aluno: ");
        scanf("%d",&((*aluno)[i].matricula));
        fwrite(&((*aluno)[i]),sizeof(struct cadastro),1,arquivo);
     }
     fclose(arquivo);
}

Acredito que esteja um pouco confuso... basicamente andei a fazer patern matching aos apontadores até acertar B).

PS: Não te esqueças que estás a gravar as estruturas em modo binário. Se abrires o ficheiro em modo texto não vais ver os números, apenas os nomes.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Uma maneira mais fácil de entender isto talvez seja declarar uma variável

cadastro *vectorAlunos

A seguir ao realloc, fazes:

vectorAlunos = *aluno;

E depois usas a vectorAlunos para aceder às posições. Deve simplificar um bocado os acessos aos campos, se a tratares como um array.

De qualquer forma, talvez seja melhor repensares essa função. Acho que essa função está a ser mal construída. Pela lógica da main deveria permitir cadastrar 1 aluno, no entanto estás é a preencher todos os alunos até à posição cont-1.

Da mesma forma, fazer a leitura do teclado e a gravação em ficheiro na mesma função é como misturar as entradas com a sobremesa. Devias ter isso separado, no meu ponto de vista.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
netinhocqc

É realmente estou confunso em realção a esse programa, tenho pouca experiencia em C.

Consegui resolver o problema de realloc, mais agora apareceu um pequeno problema, é na função imprimir, está imprimindo o ultimo cadastrado, vai o código completo com alterações.

Desde já agradeços as suas respostas.


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

typedef struct cadastro{
        char nome[30];
        int idade;
        int matricula;
}cadastro;

cadastro* preencher(cadastro **aluno, int cont);
void imprimir(cadastro *aluno);
void pesquisar(cadastro *aluno);
void criar();

int main(){
    int op;
    FILE *arquivo;
    int cont=0;
    cadastro *aluno;
    aluno = (cadastro *)malloc(sizeof(cadastro)*cont);
    criar();
    printf("\t\t\t\tCadastro de Alunos\n\n");
    do{
       printf("--------------------------------------------------------------------------------\n\n");
       printf("\t\t\t\t(1) - Cadastrar Aluno \n");
       printf("\t\t\t\t(2) - Lista Alunos \n"); 
       printf("\t\t\t\t(3) - Pesquisar Aluno \n");
       printf("\t\t\t\t(4) - Ordenar Lista\n");
       printf("\t\t\t\t(5) - Remover Alunos\n");
       printf("\t\t\t\t(6) - Sair\n\n");
       printf("--------------------------------------------------------------------------------\n\n");
       printf("Digite sua opcao: ");
       scanf("%d",&op);
       switch(op){
              case 1:
                   cont++;
                   preencher(&aluno, cont); 
                   break;
              case 2:
                   imprimir(aluno);
                   break;
              case 3:
                   pesquisar(aluno);
                   break;          
              default:
                   printf("Saindo!\n");
       }                              
    }while(op != 6);
    system("pause");
}     
void criar(){
      FILE *arquivo;
      if((arquivo = fopen("Windows.txt","wb")) == NULL){
         exit(0);
     }
     fclose(arquivo);
}
void pesquisar(cadastro *aluno){
     FILE *arquivo;
     char Npesquisa[50];
     fflush(stdin);
     if((arquivo = fopen("Windows.txt","rb")) == NULL){
         exit(0);
     }
      printf("--------------------------------------------------------------------------------\n\n");
     printf("Digite do Aluno que deseja pesquisar: ");
     fgets(Npesquisa,50,stdin); 
     printf("\n");      
     if(fread(&aluno,sizeof(struct cadastro),1,arquivo) < 1){
         exit(0);
         }
     if(strcmp(Npesquisa,aluno->nome) == 0){
        fread(&aluno,sizeof(struct cadastro),1,arquivo);                         
        printf("Nome: %sIdade: %d\nMatricula %d\n",aluno->nome, aluno->idade, aluno->matricula);
     }else{
        printf("Nome nao encontrado\n");
     } 
     fclose(arquivo);    
     printf("--------------------------------------------------------------------------------\n\n");
}        


void imprimir(cadastro *aluno){
      FILE *arquivo;
      if((arquivo = fopen("Windows.txt","rb")) == NULL){
         exit(0);
     }
     while (1) {
        if(fread(&aluno, sizeof (struct cadastro), 1, arquivo) < 1 )
           break;
        } 
        printf("Nome: %sIdade: %d\nMatricula %d\n",aluno->nome, aluno->idade, aluno->matricula);
     fclose(arquivo); 
} 
     
cadastro* preencher(cadastro **aluno, int cont){
     FILE *arquivo;
     realloc((*aluno),sizeof(cadastro)*cont);
        
     if((arquivo = fopen("Windows.txt","ab")) == NULL){
        exit(0);
     }
     fflush(stdin);
     printf("Digite o Nome do Aluno: ");
     fgets((*aluno)->nome,30,stdin);
     printf("Digite a Idade do Aluno: ");
     scanf("%d",&((*aluno)->idade));
     printf("Digite a Matricula do Aluno: ");
     scanf("%d",&((*aluno)->matricula));
     fwrite(&(*aluno),sizeof(struct cadastro),1,arquivo);
     fflush(arquivo);
     fclose(arquivo);
     return (*aluno);
}

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Estás a fazer uma confusão danada.

     while (1) {
        if(fread(&aluno, sizeof (struct cadastro), 1, arquivo) < 1 )
           break;
        } 

Este ciclo vai-te ler o ficheiro todo, mas vai guardar cada aluno na mesma posição. Ou seja, na primeira iteração Lês a primeira estrutura e guarda em aluno. Na segunda, lês a segunda estrutura e guardas por cima da primeira, em aluno, etc... A última estrutura a ser lida é a ultima a ser gravada por cima das outras, logo ao imprimires é essa que vai aparecer. 

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Nem sei por onde lhe pegar.

Primeiro, tu estás a misturar ficheiros e vectores.

Podes representar a informação no teu programa de 2 formas:

1.ª Carregas as estruturas todas para um vector, processas a informação usando o vector, e, antes de sair da aplicação voltas a gravar para ficheiro.

Vantagens: mais rápido a executar e mais fácil de programar.

Desvantagens: Usa mais memória e, se o programa crashar ou o computador se desligar, perdes as alterações.

2.ª Usas os ficheiros como o teu vector, isto é, cada alteração que é feita numa estrutura é imediatamente gravada num ficheiro.

Vantagens: Usa menos memória e a informação é permanente.

Desvantagens: Mais lento a executar e mais complexo de programar (o acesso a diferentes registos não pode ser indexado como no caso dos vectores).

Tu estás a misturar as 2, até eu me estava a trocar.

Nas tuas funções, tu estás a usar mais a 2.ª hipótese, isto é, para cada operação que queres fazer, abres o ficheiro, lês os registos, processas e voltas a gravar. Não tenho nada contra, é uma forma perfeitamente válida.

No entanto, o uso do realloc está completamente fora de contexto no teu programa. Tu usas exclusivamente a primeira posição do vector, não fazes uso das restantes, por isso nem precisas de um vector, uma variavel do tipo cadastro chega. Da mesma forma, passa variável aluno para a função que imprime, mas nunca usas o valor que lá está... Apenas a usas para gravar os dados do ficheiro. Para isso não precisas usar um argumento, uma variavel local serve perfeitamente.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.