Ir ao conteúdo
  • Cadastre-se

C Invasão de memória de uma string sobre outra string


donutLukke
Ir à solução Resolvido por donutLukke,

Posts recomendados

Boa noite pessoal, gostaria da ajuda de vocês.

 

Estou fazendo um código que pega informações do usuário, coloca em uma AVL e depois passa os dados dessa AVL para um arquivo. O problema é que quando igualo ou sobreponho as posições da string nome[ ] em relação a string cpf[ ] (ambas da struct "stc_Aluno"), parece haver uma invasão de memória da string nome[ ] em cima da string cpf[ ].

 

Por exemplo: se uso...

#define CAID 10
#define CANOME 11
#define CACPF 12

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo, *direito;
  short altura;
}stc_Aluno;

 

O código consegue detectar se o CPF digitado já está na lista de dados.

 

Já quando coloco assim...

#define CAID 10
#define CANOME 12
#define CACPF 12

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo, *direito;
  short altura;
}stc_Aluno;

 

O código não consegue detectar se o CPF digitado já está na lista de dados.

 

Primeiro o código vai para a função de "idAluno", depois "nomeAluno" e por final a "cpfAluno". Dentro das funções "idAluno" e "cpfAluno", há a função "compareAluno", que é responsável por identificar se o dado digitado já está contido na nossa AVL. No primeiro aluno adicionado, o código roda corretamente, já quando insiro os dados do segundo aluno, no momento da comparação de cpfs, a função ignora se o "cpf" digitado e o "cpf" que está na AVL são iguais.

 

Vou deixar o link do código logo abaixo, pode fazer a modificação que achar necessária e se possível, coloque aqui nesse post, o que você usou para resolver o problema. https://replit.com/join/snrbwfcatk-lucasverissimo1

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

@donutLukke    creio que seja por que a string foi declarada com onze espaços , e assim só pode armazenar dez caracteres do nome , e o último espaço reservado será usado para armazenar o newLine da tecla enter , então se você colocar a string com maior quantidade de espaços não haverá erro .

como você pode ver nesse código :

#define     _WIN32_WINNT 0x600
#define     _h GetStdHandle(STD_OUTPUT_HANDLE)
#include    <stdio.h>
#include    <stdlib.h>
#include    <conio.h>
#include    <string.h>
#include    <windows.h>
#define     CAID   10
#define     CANOME 11
#define     CACPF  12

typedef struct A
{
  char   id  [CAID  ];
  char   nome[CANOME];
  char   cpf [CACPF ];
  struct A *esquerdo ;
  struct A *direito  ;
  short  altura      ;
}        stc_Aluno   ;

int main( int Argc , char **Argv )
{
  stc_Aluno al[5];
  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;
  }
  SetConsoleTextAttribute( _h , 14 + ( 12 << 4 ) );
  strcpy(al[0].nome , "Fulano Cic"   ); /// essa string pode ter no mAximo 11 caracteres
                                        /// sendo que o Ultimo serA o newLine "\n" tecla "Enter"
  strcpy(al[0].cpf  , "12345678910"  );
  printf(" Nome -> %10s  \n Cpf  -> %10s \n",
              al[0].nome , al[0].cpf );

  SetConsoleTextAttribute( _h , cor_letra + ( cor_fundo << 4 ) );
  return 0;
}

 

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

1 hora atrás, devair1010 disse:

@donutLukke    creio que seja por que a string foi declarada com onze espaços , e assim só pode armazenar dez caracteres do nome , e o último espaço reservado será usado para armazenar o newLine da tecla enter , então se você colocar a string com maior quantidade de espaços não haverá erro .

como você pode ver nesse código :

#define     _WIN32_WINNT 0x600
#define     _h GetStdHandle(STD_OUTPUT_HANDLE)
#include    <stdio.h>
#include    <stdlib.h>
#include    <conio.h>
#include    <string.h>
#include    <windows.h>
#define     CAID   10
#define     CANOME 11
#define     CACPF  12

typedef struct A
{
  char   id  [CAID  ];
  char   nome[CANOME];
  char   cpf [CACPF ];
  struct A *esquerdo ;
  struct A *direito  ;
  short  altura      ;
}        stc_Aluno   ;

int main( int Argc , char **Argv )
{
  stc_Aluno al[5];
  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;
  }
  SetConsoleTextAttribute( _h , 14 + ( 12 << 4 ) );
  strcpy(al[0].nome , "Fulano Cic"   ); /// essa string pode ter no mAximo 11 caracteres
                                        /// sendo que o Ultimo serA o newLine "\n" tecla "Enter"
  strcpy(al[0].cpf  , "12345678910"  );
  printf(" Nome -> %10s  \n Cpf  -> %10s \n",
              al[0].nome , al[0].cpf );

  SetConsoleTextAttribute( _h , cor_letra + ( cor_fundo << 4 ) );
  return 0;
}

 

Acho que não expliquei direito: o código só roda certo quando a string nome[ ] tem o tamanho de 11 caracteres ou menos, acima disso ele fica roubando o espaço de memória da string cpf[ ], mas não consigo enxergar o motivo.

 

Se tiver tempo, vá no meu código, entre na "tbl_aluno" e escolha a opção de adicionar, primeiro você roda o código com o "CANOME = 11" e depois "CANOME = 12", adicone dois alunos em ambos os casos, e quando for adicionar o segundo aluno, repita o "cpf" que colocou para o primeiro.

 

No caso "CANOME = 11" ele vai rodar como o desejado, já no "CANOME = 12" ele vai ignorar que você colocou o mesmo "cpf" para ambos os alunos.

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

6 horas atrás, donutLukke disse:

Por exemplo: se uso...

#define CAID 10
#define CANOME 11
#define CACPF 12

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo, *direito;
  short altura;
}stc_Aluno;

 

O código consegue detectar se o CPF digitado já está na lista de dados.

 

Já quando coloco assim...

#define CAID 10
#define CANOME 12
#define CACPF 12

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo, *direito;
  short altura;
}stc_Aluno;

 

E qual seria a diferença entre os dois?

 

Não falo pelo forum mas se não postar o código aqui, ao menos um mínimo exemplo, acho que dificilmente serviria para ajudar outras pessoas com dúvidas semelhantes. A razão do forum existie é mais essa e não o suporte individualizado a problemas específicos (consultoria).

 

Sobre o que postou sugiro evitar essa notação struct A *a, *b; 

 

Em C se define o nome como sendo de um tipo e o asterisco faz parte do tipo e não do nome. E não deve declarar mais de uma variável por linha. Não ajuda em nada.

 

No seu exemplo, qual o tipo de esquerdo? esquerdo é struct A*, o que o compilador pode rapidamente te dizer.

 

E direito? direito é struct A*. E é óbvia consequência disso que *direto é struct A. Só que não é isso que está declarando.

 

E usar uma série assim gera muito erro pela facilidade de esquecer algum asterisco ou colocar um a mais, e para inicializar valores e achar variáveis.

 

Provavelmente estaria melhor com algo assim

 

typedef struct A
{
	char id[CAID];
	char nome[CANOME];
	char cpf[CACPF];
	struct A* esquerdo;
	struct A* direito;
	short altura;

}   Aluno;

 

Poste o código aqui e os passos para reproduzir o erro.

 

 

7 horas atrás, donutLukke disse:

O problema é que quando igualo ou sobreponho as posições da string nome[ ] em relação a string cpf[ ] (ambas da struct "stc_Aluno"), parece haver uma invasão de memória da string nome[ ] em cima da string cpf[ ].

 

Não consegui entender isso.

 

 

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

@donutLukke   seu código que está no Replit está com erro e não compila , e copiado para o codeblock funciona  mas veio com muitos caracteres especiais lá do site e ainda não consegui remove los do texto ,  e ali no post #2 do código que postei acima ,  ficou com o mesmo erro de antes , mas não haver esse erro seria modificar isso aqui :

#define     CAID   10
#define     CANOME 110 /// assim o nome pode ter muitas letras
#define     CACPF  12

 

Link para o comentário
Compartilhar em outros sites

5 horas atrás, arfneto disse:

 

E qual seria a diferença entre os dois?

 

Não falo pelo forum mas se não postar o código aqui, ao menos um mínimo exemplo, acho que dificilmente serviria para ajudar outras pessoas com dúvidas semelhantes. A razão do forum existie é mais essa e não o suporte individualizado a problemas específicos (consultoria).

 

Sobre o que postou sugiro evitar essa notação struct A *a, *b; 

 

Em C se define o nome como sendo de um tipo e o asterisco faz parte do tipo e não do nome. E não deve declarar mais de uma variável por linha. Não ajuda em nada.

 

No seu exemplo, qual o tipo de esquerdo? esquerdo é struct A*, o que o compilador pode rapidamente te dizer.

 

E direito? direito é struct A*. E é óbvia consequência disso que *direto é struct A. Só que não é isso que está declarando.

 

E usar uma série assim gera muito erro pela facilidade de esquecer algum asterisco ou colocar um a mais, e para inicializar valores e achar variáveis.

 

Provavelmente estaria melhor com algo assim

 

typedef struct A
{
	char id[CAID];
	char nome[CANOME];
	char cpf[CACPF];
	struct A* esquerdo;
	struct A* direito;
	short altura;

}   Aluno;

 

Poste o código aqui e os passos para reproduzir o erro.

 

 

 

Não consegui entender isso.

 

 

Ok, o passo a passo.

 

1º passo: clicar na opção 1 (tbl_Aluno) que te direcionará para o menu de 6 opções onde você escolherá a opção 1 novamente (Adicionar Aluno).

 

{
      // Funcionalidades para a tabela aluno.
      case 1:
        do{
          fprintf(stdout, "\n📗O que você deseja fazer na tabela ALUNO?\n\n1️⃣ Adicionar aluno\n2️⃣ Procurar aluno\n3️⃣ Remover aluno\n4️⃣ Alterar informação do aluno\n5️⃣ Imprimir alunos\n6️⃣ Voltar\n\nR ▶ ");
          fscanf(stdin, "%d", &a);
          printf("\n");
          switch(a)
          {
            case 1: 
              do{
                strcpy(aluno.id, idAluno(student, 1));
                strcpy(aluno.nome, nomeAluno(student));
                strcpy(aluno.cpf, cpfAluno(student, 1));
                // Adiciona os dados na AVL.
                student = adicionaAluno(student, aluno.id, aluno.nome, aluno.cpf);
                remove("aluno.bin");
                salvarAluno(&student);
                printf("\n📢Aluno salvo com sucesso🎶\n\n");
                printf("\nGostaria de adicionar outro aluno?\n\n✔ SIM\t\t✖ NÃO\n\nR ▶ ");
                scanf(" %c", &b);
                printf("\n");
              }while(b == 'V' || b == 'v');
              break;
              ...
           }
          ...
       }
  ...
  }

 

2° passo: adicione dois alunos como ilustrado na imagem 1, mas seguindo essas configurações que estão no início do código, dessa forma o código consegue detectar se o cpf digitado já existe no banco de dados:

 

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

#define CAID 10
#define CANOME 11
#define CACPF 12

#define CCID 4
#define CCNOME 25


typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo;
  struct A *direito;
  short altura;
}stc_Aluno;

 

3° passo: adicione dois alunos como ilustrado na imagem 2, mas seguindo essas configurações que estão no início do código, dessa forma o código não consegue detectar se o cpf digitado já existe no banco de dados:

 

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

#define CAID 10
#define CANOME 12
#define CACPF 12

#define CCID 4
#define CCNOME 25


typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo;
  struct A *direito;
  short altura;
}stc_Aluno;

 

Até se CANOME > 12 o código também não funciona direito.

 

No momento de adicionar os alunos, o código percorre as seguintes funções respectivamente:

 

int main(void);
char* idAluno(stc_Aluno *a, int opcao);
int compareAluno(stc_Aluno **a, char variavel[ ]);
char* nomeAluno(stc_Aluno *a);
int compareAluno(stc_Aluno **a, char variavel[ ]);
char* cpfAluno(stc_Aluno *a, int opcao);
int compareAluno(stc_Aluno **a, char variavel[ ]);
stc_Aluno* adicionaAluno(stc_Aluno *a, char id[], char nome[], char cpf[]);
void salvarAluno(stc_Aluno **a);

 

No caso do id ou cpf serem iguais, a função "compareAluno" deve/deveria retornar 1.

 

E sempre que for fazer um teste, apague o "arquivo.bin" criado anteriormente, ele fica abaixo da "main.c", é só clicar nos 3 pontinhos que aparece as opções.

 

Imagem 1.png

 

Imagem 2.png

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

@donutLukke ilustrou bem o problema, mas não entendi o parágrafo que citei  e nem a diferença entre os dois blocos iguais. E ainda não tem o código para que alguém que queira ajudar possa recortar e colar sem sair do site e se inscrever em outro para poder afinal ver o programa em https://replit.com/login que pode até ter sido alterado e segundo @devair1010 sequer compila hoje.  

 

8 horas atrás, devair1010 disse:

seu código que está no Replit está com erro e não compila , e copiado para o codeblock funciona  mas veio com muitos caracteres especiais lá do site e ainda não consegui remove los do texto

 

pois é. E ainda foi preciso editar o texto copiado e remover coisas.

 

Como te disse outros aqui poderiam se beneficiar do tópico. E seria muito mais simples usar o botão code como explicado no primeiro post desse forum: isso garantia o aspecto público do código e evitaria a possibilidade de caracteres de controle virem no meio do texto...

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

5 minutos atrás, arfneto disse:

@donutLukke ilustrou bem o problema, mas não entendi o parágrafo que citei  e nem a diferença entre os dois blocos iguais. E ainda não tem o código para que alguém que queira ajudar possa recortar e colar sem sair do site e se inscrever em outro para poder afinal ver o programa em https://replit.com/login que pode até ter sido alterado e segundo @devair1010 sequer compila hoje.  

 

 

pois é. E ainda foi preciso editar o texto copiado e remover coisas.

 

Como te disse outros aqui poderiam se beneficiar do tópico. E seria muito mais simples usar o botão code como explicado no primeiro post desse forum: isso garantia o aspecto público do código e evitaria a possibilidade de caracteres de controle virem no meio do texto...

 

Ok, vou reconfigurar o código e daqui a pouco posto aqui, desculpe a minha burrice ou ingenuidade.

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

@donutLukke Hey não me leve a mal. E sequer falo em nome do forum. Apenas deixei uma opinião. Se postar o material aqui eu por exemplo vou rever seu programa 😄  mas não vou entrar em outro site para isso, a menos talvez de ter um mínimo aqui e de o site ser o GitHub 😉 porque aí se pode importar o projeto inteiro com um click só 🙂 

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

14 minutos atrás, arfneto disse:

@donutLukke ilustrou bem o problema, mas não entendi o parágrafo que citei  e nem a diferença entre os dois blocos iguais. E ainda não tem o código para que alguém que queira ajudar possa recortar e colar sem sair do site e se inscrever em outro para poder afinal ver o programa em https://replit.com/login que pode até ter sido alterado e segundo @devair1010 sequer compila hoje.  

 

 

pois é. E ainda foi preciso editar o texto copiado e remover coisas.

 

Como te disse outros aqui poderiam se beneficiar do tópico. E seria muito mais simples usar o botão code como explicado no primeiro post desse forum: isso garantia o aspecto público do código e evitaria a possibilidade de caracteres de controle virem no meio do texto...

 

Em relação a isto:

 

Citação

O problema é que quando igualo ou sobreponho as posições da string nome[ ] em relação a string cpf[ ] (ambas da struct "stc_Aluno"), parece haver uma invasão de memória da string nome[ ] em cima da string cpf[ ].

 

Acredito que me pronunciei da forma errada, na verdade é quando igualo ou sobreponho o tamanho da string nome[ ] em relação a string cpf[ ], por exemplo: quando CANOME é <= 11, o código roda corretamente.

 

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

#define CAID 10
#define CANOME 11  // <= 11 o código funciona
#define CACPF 12

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo;
  struct A *direito;
  short altura;
}stc_Aluno;

 

Já quando CANOME >= 12 o código não consegue mais detectar se o CPF digitado já existe no banco de dados.

 

#include <string.h>
#include <ctype.h>

#define CAID 10
#define CANOME 12  // >= 12 o código não funciona
#define CACPF 12

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo;
  struct A *direito;
  short altura;
}stc_Aluno;

 

Abaixo estarei enviando o código em arquivo.txt, tirei os caracteres emojis para uma melhor visualização nos compiladores.

Código.txt

8 minutos atrás, arfneto disse:

@donutLukke Hey não me leve a mal. E sequer falo em nome do forum. Apenas deixei uma opinião. Se postar o material aqui eu por exemplo vou rever seu programa 😄  mas não vou entrar em outro site para isso, a menos talvez de ter um mínimo aqui e de o site ser o GitHub 😉 porque aí se pode importar o projeto inteiro com um click só 🙂 

 

Eu aceito qualquer crítica, levo como aprendizado, sua opinião importa muito para mim.

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

@donutLukke

11 minutos atrás, donutLukke disse:

Abaixo estarei enviando o código em arquivo.txt, tirei os caracteres emojis para uma melhor visualização nos compiladores

 

Acho que não me expliquei bem mesmo. Um download já é sair do site. É disso que estou falando:

 

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

#define CAID 10
#define CANOME 12
#define CACPF 12

#define CCID 4
#define CCNOME 25


typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo;
  struct A *direito;
  short altura;
}stc_Aluno;

typedef struct C
{
  char id[CCID];
  char nome[CCNOME];
  char departamento[5];
  int creditos;
  struct C *esquerdo;
  struct C *direito;
  short altura;
}stc_Curso;

typedef struct AC
{
  char id_aluno[10];
  char id_curso[10];
  int creditos;
  struct AC *esquerdo, *direito;
  short altura;
}stc_AlunoCurso;


/*
   Retorna o maior dentre dois valores
   a, b -> altura de dois nós da árvore.
*/
short maior(short a, short b){
  return (a > b)? a: b;
}

// Retorna a altura de um nó ou -1 caso ele seja null.
short alturaAluno(stc_Aluno *a){
  if(a == NULL)
    return -1;
  else
    return a->altura;
}

// Calcula e retorna o fator de balanceamento de um nó.
short fatorDeBalanceamentoAluno(stc_Aluno *a){
  if(a)
    return (alturaAluno(a->esquerdo) - alturaAluno(a->direito));
  else
    return 0;
}

// ----------- ROTAÇÕES -----------

// Função para a rotação à esquerda.
stc_Aluno* rotacaoEsquerdaAluno(stc_Aluno *a){
  stc_Aluno *b, *c;
  b = a->direito;
  c = b->esquerdo;
  b->esquerdo = a;
  a->direito = c;
  a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
  b->altura = maior(alturaAluno(b->esquerdo), alturaAluno(b->direito)) + 1;
  return b;
}

// Função para a rotação à direita.
stc_Aluno* rotacaoDireitaAluno(stc_Aluno *a){
  stc_Aluno *b, *c;
  b = a->esquerdo;
  c = b->direito;
  b->direito = a;
  a->esquerdo = c;
  a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
  b->altura = maior(alturaAluno(b->esquerdo), alturaAluno(b->direito)) + 1;
  return b;
}

stc_Aluno* rotacaoEsquerdaDireitaAluno(stc_Aluno *a){
  a->esquerdo = rotacaoEsquerdaAluno(a->esquerdo);
  return rotacaoDireitaAluno(a);
}

stc_Aluno* rotacaoDireitaEsquerdaAluno(stc_Aluno *a){
  a->direito = rotacaoDireitaAluno(a->direito);
  return rotacaoEsquerdaAluno(a);
}

/*
   Função para realizar o balanceamento da árvore após uma inserção ou remoção
   Recebe o nó que está desbalanceado e retorna a nova raiz após o balanceamento.
*/
stc_Aluno* balancearAluno(stc_Aluno *a){
  short fb = fatorDeBalanceamentoAluno(a);
  // Rotação à esquerda.
  if(fb < -1 && fatorDeBalanceamentoAluno(a->direito) <= 0)
    a = rotacaoEsquerdaAluno(a);
  // Rotação à direita.
  else if(fb > 1 && fatorDeBalanceamentoAluno(a->esquerdo) >= 0)
    a = rotacaoDireitaAluno(a);
  // Rotação dupla à esquerda.
  else if(fb > 1 && fatorDeBalanceamentoAluno(a->esquerdo) < 0)
    a = rotacaoEsquerdaDireitaAluno(a);
  // Rotação dupla à direita.
  else if(fb < -1 && fatorDeBalanceamentoAluno(a->direito) > 0)
    a = rotacaoDireitaEsquerdaAluno(a);
  return a;
}

// Função que adiciona um novo aluno.
stc_Aluno* novoAluno(char id[], char nome[], char cpf[]){
  stc_Aluno *novo = malloc(sizeof(stc_Aluno));
  if(novo){
    strcpy(novo->id,id);
    strcpy(novo->nome,nome);
    strcpy(novo->cpf,cpf);
    novo->esquerdo = NULL;
    novo->direito = NULL;
    novo->altura = 0;
  }
  else
    printf("\nErro ao adicionar novo aluno\n");
  return novo;
}

// Função que adiciona um aluno.
stc_Aluno* adicionaAluno(stc_Aluno *a, char id[], char nome[], char cpf[]){
  if(a == NULL) 
    return novoAluno(id, nome, cpf);
  else{ 
    if(atof(id) < atof(a->id))
      a->esquerdo = adicionaAluno(a->esquerdo, id, nome, cpf);
    else if(atof(id) > atof(a->id))
      a->direito = adicionaAluno(a->direito, id, nome, cpf);
  }
  // Recalcula a altura de todos os nós entre a raiz e o novo nó inserido.
  a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
  // Verifica a necessidade de rebalancear a árvore.
  a = balancearAluno(a);
  return a;
}

// Função que remove um aluno pelo ID ou CPF.
stc_Aluno* removeAluno(stc_Aluno *a, char variavel[], int opcao){
  if(a == NULL){
    if(strlen(variavel) == (CAID-1)){
      printf("\nO ID digitado não existe no banco de dados\n");
      return NULL;
    }
  } 
  else{ 
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(a->id, variavel) == 0){
        if(a->esquerdo == NULL && a->direito == NULL){
          if(opcao)
            printf("\nAluno removido com sucesso\n");
          free(a);
          return NULL;
        }
        else{
          if(a->esquerdo != NULL && a->direito != NULL){
            stc_Aluno *aux = a->esquerdo;
            while(aux->direito != NULL)
              aux = aux->direito;
            strcpy(a->id, aux->id);
            strcpy(aux->id, variavel);
            strcpy(a->nome, aux->nome);
            strcpy(a->cpf, aux->cpf);
            a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
            return a;
          }
          else{
            stc_Aluno *aux;
            if(a->esquerdo != NULL)
              aux = a->esquerdo;
            else
              aux = a->direito;
            if(opcao)
              printf("\nAluno removido com sucesso\n");
            free(a);
            return aux;
          }
        }
      }
      else{
        if(atof(variavel) < atof(a->id))
          a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
        else
          a->direito = removeAluno(a->direito, variavel, opcao);
      }
    }  
    else if(strlen(variavel) == (CACPF-1)){
      if(strcmp(a->cpf, variavel) == 0){
        if(a->esquerdo == NULL && a->direito == NULL){
          if(opcao)
            printf("\nAluno removido com sucesso\n");
          free(a);
          return NULL;
        }
        else{
          if(a->esquerdo != NULL && a->direito != NULL){
            stc_Aluno *aux = a->esquerdo;
            while(aux->direito != NULL)
              aux = aux->direito;
            strcpy(a->cpf, aux->cpf);
            strcpy(aux->cpf, variavel);
            strcpy(a->nome, aux->nome);
            strcpy(a->id, aux->id);
            a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
            return a;
          }
          else{
            stc_Aluno *aux;
            if(a->esquerdo != NULL)
              aux = a->esquerdo;
            else
              aux = a->direito;
            if(opcao)
              printf("\nAluno removido com sucesso\n");
            free(a);
            return aux;
          }
        }
      }
      else{
        a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
        a->direito = removeAluno(a->direito, variavel, opcao);
      }
    }
    // Recalcula a altura de todos os nós entre a raiz e o novo nó inserido.
    a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
    // Verifica a necessidade de rebalancear a árvore.
    a = balancearAluno(a);
    return a;
  }
  return a;
}

// Função para imprimir dados.
int imprimeAluno(int i, char variavel[]){
  FILE *arq_aluno;
  stc_Aluno aluno;
  arq_aluno = fopen("aluno.bin","a+b");
  printf("\t\t\t\t\t\t  LISTA DE ALUNOS\n");
  printf("\t-----------------------------------------------------------\n");
  printf("\t|\t ID\t\t| \t  CPF\t  | \t\t\t NOME\t\t\t  |\n");
  printf("\t-----------------------------------------------------------\n");
  while(fread(&aluno, 1, sizeof(stc_Aluno), arq_aluno) > 0){
    if(i == 1){
      if(strcmp(aluno.id, variavel) == 0){
        printf("\t%s | %s | %s \n", aluno.id, aluno.cpf, aluno.nome);
        printf("\t-----------------------------------------------------------\n\n");
        return 1;
      }
    }
    else
      printf("\t%s | %s | %s \n", aluno.id, aluno.cpf, aluno.nome);
  }
  printf("\t-----------------------------------------------------------\n\n");
  return 1;
}

// Função para salvar os dados no arquivo.
void salvarAluno(stc_Aluno **a){
  FILE *arq_aluno;
  stc_Aluno aluno;
  int temp;
  if(*a!=NULL){
    salvarAluno(&(*a)->esquerdo);
    arq_aluno = fopen("aluno.bin","a+b");
    strcpy(aluno.id, (*a)->id);
    strcpy(aluno.nome, (*a)->nome);
    strcpy(aluno.cpf, (*a)->cpf);
    temp = fwrite(&aluno, 1, sizeof(stc_Aluno), arq_aluno);
    if (!temp)
      printf ("Erro ao salvar\n");
    fclose(arq_aluno);
    salvarAluno(&(*a)->direito);
  }
}

// Função para procurar um aluno pelo ID, NOME ou CPF.
int procureAluno(stc_Aluno **a, char variavel[]){
  if(*a != NULL){
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(variavel, (*a)->id) == 0){
        printf("\nID: %s\nNome: %s\nCPF: %s\n\n", (*a)->id, (*a)->nome, (*a)->cpf);
      }
      else if(atof(variavel) < atof((*a)->id))
        return procureAluno(&(*a)->esquerdo, variavel);
      else if(atof(variavel) > atof((*a)->id))
        return procureAluno(&(*a)->direito, variavel);
    }
    else if(strlen(variavel) <= (CANOME-1)){
      procureAluno(&(*a)->esquerdo, variavel);
      procureAluno(&(*a)->direito, variavel);
      if(strcmp(variavel, (*a)->nome) == 0)
        printf("\nID: %s\nNome: %s\nCPF: %s\n\n", (*a)->id, (*a)->nome, (*a)->cpf);
    }  
    else if(strlen(variavel) == (CACPF-1)){
      procureAluno(&(*a)->esquerdo, variavel);
      procureAluno(&(*a)->direito, variavel);
      if(strcmp(variavel, (*a)->cpf) == 0)
        printf("\nID: %s\nNome: %s\nCPF: %s\n\n", (*a)->id, (*a)->nome, (*a)->cpf);
    }
  return 1;
  }
  else
    return 0;
}

// Verifica se o ID, NOME ou CPF digitado existe no banco de dados.
int compareAluno(stc_Aluno **a, char variavel[]){
  int i, j, aux = 0; 
  if(*a != NULL){
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(variavel, (*a)->id) == 0)
        return 1;
      else if(atof(variavel) < atof((*a)->id))
        i = compareAluno(&(*a)->esquerdo, variavel);
      else if(atof(variavel) > atof((*a)->id))
        j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(strlen(variavel) <= (CANOME-1)){
      if(strcmp(variavel, (*a)->nome) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel);
      int j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(strlen(variavel) == (CACPF-1)){
      if(strcmp((*a)->cpf, variavel) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel);
      int j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
  }
  else{
    if(aux == 1)
      return aux;
  }
  return aux;
}

// Guarda em uma variável o ID digitado.
char* idAluno(stc_Aluno *a, int opcao){
  stc_Aluno aluno;
  int b, c, d, e;
  char *dado = malloc(sizeof(char)*CAID);
  if(opcao == 1){
    // Recebe conteúdo ID.
    printf("\nDigite o ID do aluno (%d dígitos): ", CAID-1);
    scanf(" %s", aluno.id);
    // Verifica se o ID possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.id[b] != '\0'; b++){
      if(!isdigit(aluno.id[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o ID possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.id[b] != '\0'; b++)
      d++;
    e = compareAluno(&a, aluno.id);
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != (CAID-1) || e == 1){
      e = compareAluno(&a, aluno.id);
      if(e == 1)
        printf("\nEste ID já está em uso\n");
      printf("\nID inválido, digite novamente\n");
      printf("\nID (%d dígitos): ", CAID-1);
      scanf(" %s", aluno.id);
      c = 0;
      d = 0;
      for( b = 0; aluno.id[b] != '\0'; b++){
        if(!isdigit(aluno.id[b])){
          c = 1;
          break;
        }
      }
      for( b = 0; aluno.id[b] != '\0'; b++)
        d++;
      e = compareAluno(&a, aluno.id);
    }
  }
  else if(opcao == 2){
    // Recebe conteúdo ID.
    printf("Digite o ID do aluno (%d dígitos): ", CAID-1);
    scanf(" %s", aluno.id);
    // Verifica se o ID possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.id[b] != '\0'; b++){
      if(!isdigit(aluno.id[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o ID possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.id[b] != '\0'; b++)
      d++;
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != (CAID-1)){
      printf("\nID inválido, digite novamente\n");
      printf("\nID (%d dígitos): ", CAID-1);
      scanf(" %s", aluno.id);
      c = 0;
      d = 0;
      for( b = 0; aluno.id[b] != '\0'; b++){
        if(!isdigit(aluno.id[b])){
          c = 1;
          break;
        } 
      }
      for( b = 0; aluno.id[b] != '\0'; b++)
        d++;
    }
  }
  strcpy(dado, aluno.id);
  return dado;
}

// Guarda em uma variável o NOME digitado.
char* nomeAluno(stc_Aluno *a){
  stc_Aluno aluno;
  int b, c, d;
  char *dado = malloc(sizeof(char)*CANOME);
  // Recebe conteúdo NOME.
  printf("Digite o NOME do aluno (%d dígitos): ", CANOME-1);
  scanf(" %[^\n]s", aluno.nome);
  // Verifica se o NOME possui quantidade correta de caracteres.
  c = 0;
  for( b = 0; aluno.nome[b] != '\0'; b++){
    if(!islower(aluno.nome[b]))
      if(!isupper(aluno.nome[b])){
        if(!isspace(aluno.nome[b])){
          c = 1;
          break;
        }
      }
  }
  // Verifica se o NOME possui quantidade correta de caracteres.
  d = 0;
  for( b = 0; aluno.nome[b] != '\0'; b++)
    d++;
  // Repete a pergunta no caso de dado inválido.
  while(c == 1 || d > (CANOME-1)){
    printf("\nNOME inválido, digite novamente\n");
    printf("\nNome (%d dígitos): ", CANOME-1);
    scanf(" %[^\n]s", aluno.nome);
    c = 0;
    d = 0;
    for( b = 0; aluno.nome[b] != '\0'; b++){
      if(!islower(aluno.nome[b]))
        if(!isupper(aluno.nome[b])){
          if(!isspace(aluno.nome[b])){
            c = 1;
            break;
          }
        }
    }
    for( b = 0; aluno.nome[b] != '\0'; b++)
      d++;
  }
  strcpy(dado, aluno.nome);
  return dado;
}

// Guarda em uma variável o CPF digitado.
char* cpfAluno(stc_Aluno *a, int opcao){
  stc_Aluno aluno;
  int b, c, d, e;
  char *dado = malloc(sizeof(char)*CACPF);
  if(opcao == 1){
    // Recebe conteúdo CPF.
    printf("Digite o CPF do aluno (%d dígitos): ", CACPF-1);
    scanf(" %s", aluno.cpf);
    // Verifica se o CPF possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++){
      if(!isdigit(aluno.cpf[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o CPF possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++)
      d++;
    e = compareAluno(&a, aluno.cpf);
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != (CACPF-1) || e == 1){
      e = compareAluno(&a, aluno.cpf);
      if(e == 1)
        printf("\nEste CPF já está em uso\n");
      printf("\nCPF inválido, digite novamente\n");
      printf("\nCPF (%d dígitos): ", CACPF-1);
      scanf(" %s", aluno.cpf);
      c = 0;
      d = 0;
      for( b = 0; aluno.cpf[b] != '\0'; b++){
        if(!isdigit(aluno.cpf[b])){
          c = 1;
          break;
        }
      }
      for( b = 0; aluno.cpf[b] != '\0'; b++)
        d++;
      e = compareAluno(&a, aluno.cpf);
    }
  }
  else if(opcao == 2){
    // Recebe conteúdo CPF.
    printf("Digite o CPF do aluno (%d dígitos): ", CACPF-1);
    scanf(" %s", aluno.cpf);
    // Verifica se o CPF possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++){
      if(!isdigit(aluno.cpf[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o CPF possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++)
      d++;
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != CACPF-1){
      printf("\nCPF inválido, digite novamente\n");
      c = CACPF-1;
      printf("\nCPF (%d dígitos): ", c);
      scanf(" %s", aluno.cpf);
      c = 0;
      d = 0;
      for( b = 0; aluno.cpf[b] != '\0'; b++){
        if(!isdigit(aluno.cpf[b])){
          c = 1;
          break;
        }
      }
      for( b = 0; aluno.cpf[b] != '\0'; b++)
        d++;
    }
  }
  strcpy(dado, aluno.cpf);
  return dado;
}

// Altera um dado do aluno que o usuário escolher pelo seu ID.
stc_Aluno* alteraAluno(stc_Aluno **a, stc_Aluno **A, char variavel[], int opcao){
  char id[CAID], nome[CANOME], cpf[CACPF];
  if(*a != NULL){
    if(opcao == 1){
      if(strcmp(variavel, (*a)->id) == 0){
        strcpy(nome, (*a)->nome);
        strcpy(cpf, (*a)->cpf);
        strcpy(id, idAluno(*A, 1));
        *A = removeAluno(*A, (*a)->id, 0);
        *A = adicionaAluno(*A, id, nome, cpf);
        remove("aluno.bin");
        salvarAluno(&(*A));
        printf("\nID salvo com sucesso\n");
      }
      else if(atof(variavel) < atof((*a)->id))
        alteraAluno(&(*a)->esquerdo, &(*A), variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        alteraAluno(&(*a)->direito, &(*A), variavel, opcao);
    }
    else if(opcao == 2){
      if(strcmp(variavel, (*a)->id) == 0){
        strcpy((*a)->nome, nomeAluno(*A));
        remove("aluno.bin");
        salvarAluno(&(*A));
        printf("\nNOME salvo com sucesso\n");
      }
      else if(atof(variavel) < atof((*a)->id))
        alteraAluno(&(*a)->esquerdo, &(*A), variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        alteraAluno(&(*a)->direito, &(*A), variavel, opcao);
    }
    else if(opcao == 3){
      if(strcmp(variavel, (*a)->id) == 0){
        strcpy((*a)->cpf, cpfAluno(*A, 1));
        remove("aluno.bin");
        salvarAluno(&(*A));
        printf("\nCPF salvo com sucesso\n");
      }
      else if(atof(variavel) < atof((*a)->id))
        alteraAluno(&(*a)->esquerdo, &(*A), variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        alteraAluno(&(*a)->direito, &(*A), variavel, opcao);
    }
  }
  return *A;
}
  

int main(void) 
{
  FILE *arq_aluno, *arq_curso, *arq_alunoCurso;
  stc_Aluno aluno, *student = NULL;
  int a;
  char b;

  arq_aluno = fopen("aluno.bin","rb");
  if(!arq_aluno)
    printf("\nErro na abertura do arquivo da tabela ALUNO\nAdicione um aluno!\n");
  else{
    while(fread(&aluno,1,sizeof(stc_Aluno),arq_aluno) > 0)
      // Readiciona os dados na AVL.
      student = adicionaAluno(student, aluno.id, aluno.nome, aluno.cpf);
  }
    
  arq_curso = fopen("curso.bin","rb");
  if(!arq_curso)
    printf("\nErro na abertura do arquivo da tabela CURSO\nAdicione um curso!\n");
  
  arq_alunoCurso = fopen("alunoCurso.bin","rb");
  if(!arq_alunoCurso)
    printf("\nErro na abertura do arquivo da tabela ALUNO_CURSO\nAdicione um curso e um aluno!\n");

  do{
    fprintf(stdout, "\nDeseja usar qual tabela?\n\n1-tbl_aluno\n2-tbl_curso\n3-tbl_alunocurso\n\nR : ");
    fscanf(stdin, "%d", &a);
    printf("\n");
    switch(a)
    {
      // Funcionalidades para a tabela aluno.
      case 1:
        do{
          fprintf(stdout, "\nO que você deseja fazer na tabela ALUNO?\n\n1-Adicionar aluno\n2-Procurar aluno\n3-Remover aluno\n4-Alterar informação do aluno\n5-Imprimir alunos\n6-Voltar\n\nR : ");
          fscanf(stdin, "%d", &a);
          printf("\n");
          switch(a)
          {
            case 1: 
              do{
                strcpy(aluno.id, idAluno(student, 1));
                strcpy(aluno.nome, nomeAluno(student));
                strcpy(aluno.cpf, cpfAluno(student, 1));
                // Adiciona os dados na AVL.
                student = adicionaAluno(student, aluno.id, aluno.nome, aluno.cpf);
                remove("aluno.bin");
                salvarAluno(&student);
                printf("\nAluno salvo com sucesso\n\n");
                printf("\nGostaria de adicionar outro aluno?\n\n1 SIM\t\t2 NÃO\n\nR : ");
                scanf(" %c", &b);
                printf("\n");
              }while(b == '1');
              break;

            case 2:
              do{
                fprintf(stdout, "\nComo você deseja procurar o aluno?\n\n1-ID\n2-Nome\n3-CPF\n4-Voltar\n\nR : ");
                fscanf(stdin, "%d", &a);
                printf("\n");
                switch(a)
                {
                  case 1: 
                    strcpy(aluno.id, idAluno(student, 2));
                    // Procura os dados relacionados ao ID digitado.
                    if(procureAluno(&student, aluno.id) != 1)
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;

                  case 2:
                    strcpy(aluno.nome, nomeAluno(student));
                    // Procura os dados relacionados ao NOME digitado.
                    if(compareAluno(&student, aluno.nome) == 1)
                      procureAluno(&student, aluno.nome);
                    else
                      printf("\nO NOME digitado não existe no banco de dados\n\n");
                    break;

                  case 3:
                    strcpy(aluno.cpf, cpfAluno(student, 2));
                    // Procura os dados relacionados ao CPF digitado.
                    if(compareAluno(&student, aluno.cpf) == 1)
                      procureAluno(&student, aluno.cpf);
                    else
                      printf("\nO CPF digitado não existe no banco de dados\n\n");
                    break;

                  case 4:
                    b = '2';
                    break;

                  default:
                    printf("Opção inválida\n\n");
                    a = 1;
                  
                }
              }while( a == 1 || a == 2 || a == 3 );
              break; 

            case 3:
              do{
                fprintf(stdout, "\nComo você deseja remover o aluno?\n\n1-ID\n2-CPF\n3-Voltar\n\nR : ");
                fscanf(stdin, "%d", &a);
                switch(a)
                {
                  case 1:
                    printf("\n");
                    imprimeAluno(0, NULL);
                    printf("\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    student = removeAluno(student, aluno.id, 1);
                    remove("aluno.bin");
                    salvarAluno(&student);
                    printf("\n");
                    b = 'X';
                    break;

                  case 2:
                    printf("\n");
                    imprimeAluno(0, NULL);
                    printf("\n");
                    strcpy(aluno.cpf, cpfAluno(student, 2));
                    if(compareAluno(&student, aluno.cpf) == 1){
                      student = removeAluno(student, aluno.cpf, 1);
                      remove("aluno.bin");
                      salvarAluno(&student);
                      printf("\n");
                    }
                    else
                      printf("\nO CPF digitado não existe no banco de dados\n\n");
                    b = '2';
                    break;

                  case 3:
                    b = '2';
                    printf("\n");
                    break;

                  default:
                    printf("\nOpção inválida\n\n");
                    a = 1;
                    
                }
              }while( a == 1 || a == 2 );
              break;

            case 4:
              do{
                fprintf(stdout, "\nQual informação você deseja alterar do aluno?\n\n1-ID\n2-Nome\n3-CPF\n4-Voltar\n\nR : ");
                fscanf(stdin, "%d", &a);
                printf("\n");
                switch(a)
                {
                  case 1: 
                    printf("ID que deseja alterar\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    printf("\n\n");
                    imprimeAluno(1, aluno.id);
                    if(compareAluno(&student, aluno.id) == 1){
                      printf("\nNovo ID do aluno");
                      student = alteraAluno(&student, &student, aluno.id, 1);
                      printf("\n");
                    }
                    else
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;

                  case 2:
                    printf("ID do aluno que deseja alterar o nome\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    printf("\n\n");
                    imprimeAluno(1, aluno.id);
                    if(compareAluno(&student, aluno.id) == 1){
                      printf("\nNovo NOME do aluno\n");
                      student = alteraAluno(&student, &student, aluno.id, 2);
                      printf("\n");
                    }
                    else
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;

                  case 3:
                    printf("ID do aluno que deseja alterar o cpf\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    printf("\n\n");
                    imprimeAluno(1, aluno.id);
                    if(compareAluno(&student, aluno.id) == 1){
                      printf("\nNovo CPF do aluno\n");
                      student = alteraAluno(&student, &student, aluno.id, 3);
                      printf("\n");
                    }
                    else
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;
                  
                  case 4:
                    b = '2';
                    break;

                  default:
                    printf("Opção inválida\n\n");
                    a = 1;
                  
                }
              }while( a == 1 || a == 2 || a == 3 );
              break;

            case 5:
              imprimeAluno(0, NULL);
              b = '2';
              break;

            case 6:
              b = 0;
              a = 1;
              break;

            default:
              printf("Opção inválida\n\n");
              b = '2';
          }
        }while(b == '2');

      // Funcionalidades para a tabela curso.
      case 2:
        break;

      case 3:
        break;

      default:
        printf("Opção inválida\n\n");
        a = 1;
      
    }
  }while( a == 1 || a == 2 || a == 3 );
  
  return 0;
}
  

 

 

O simples. Depois vou ver o código. 

Se você posta o cõdigo todo mundo pode ler, aprender algo ou copiar. Se você posta um quadradinho escrito "codigo.txt"  não é nada parecido

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

2 minutos atrás, arfneto disse:

@donutLukke

 

Acho que não me expliquei bem mesmo. Um download já é sair do site. É disso que estou falando:

 

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

#define CAID 10
#define CANOME 12
#define CACPF 12

#define CCID 4
#define CCNOME 25


typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo;
  struct A *direito;
  short altura;
}stc_Aluno;

typedef struct C
{
  char id[CCID];
  char nome[CCNOME];
  char departamento[5];
  int creditos;
  struct C *esquerdo;
  struct C *direito;
  short altura;
}stc_Curso;

typedef struct AC
{
  char id_aluno[10];
  char id_curso[10];
  int creditos;
  struct AC *esquerdo, *direito;
  short altura;
}stc_AlunoCurso;


/*
   Retorna o maior dentre dois valores
   a, b -> altura de dois nós da árvore.
*/
short maior(short a, short b){
  return (a > b)? a: b;
}

// Retorna a altura de um nó ou -1 caso ele seja null.
short alturaAluno(stc_Aluno *a){
  if(a == NULL)
    return -1;
  else
    return a->altura;
}

// Calcula e retorna o fator de balanceamento de um nó.
short fatorDeBalanceamentoAluno(stc_Aluno *a){
  if(a)
    return (alturaAluno(a->esquerdo) - alturaAluno(a->direito));
  else
    return 0;
}

// ----------- ROTAÇÕES -----------

// Função para a rotação à esquerda.
stc_Aluno* rotacaoEsquerdaAluno(stc_Aluno *a){
  stc_Aluno *b, *c;
  b = a->direito;
  c = b->esquerdo;
  b->esquerdo = a;
  a->direito = c;
  a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
  b->altura = maior(alturaAluno(b->esquerdo), alturaAluno(b->direito)) + 1;
  return b;
}

// Função para a rotação à direita.
stc_Aluno* rotacaoDireitaAluno(stc_Aluno *a){
  stc_Aluno *b, *c;
  b = a->esquerdo;
  c = b->direito;
  b->direito = a;
  a->esquerdo = c;
  a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
  b->altura = maior(alturaAluno(b->esquerdo), alturaAluno(b->direito)) + 1;
  return b;
}

stc_Aluno* rotacaoEsquerdaDireitaAluno(stc_Aluno *a){
  a->esquerdo = rotacaoEsquerdaAluno(a->esquerdo);
  return rotacaoDireitaAluno(a);
}

stc_Aluno* rotacaoDireitaEsquerdaAluno(stc_Aluno *a){
  a->direito = rotacaoDireitaAluno(a->direito);
  return rotacaoEsquerdaAluno(a);
}

/*
   Função para realizar o balanceamento da árvore após uma inserção ou remoção
   Recebe o nó que está desbalanceado e retorna a nova raiz após o balanceamento.
*/
stc_Aluno* balancearAluno(stc_Aluno *a){
  short fb = fatorDeBalanceamentoAluno(a);
  // Rotação à esquerda.
  if(fb < -1 && fatorDeBalanceamentoAluno(a->direito) <= 0)
    a = rotacaoEsquerdaAluno(a);
  // Rotação à direita.
  else if(fb > 1 && fatorDeBalanceamentoAluno(a->esquerdo) >= 0)
    a = rotacaoDireitaAluno(a);
  // Rotação dupla à esquerda.
  else if(fb > 1 && fatorDeBalanceamentoAluno(a->esquerdo) < 0)
    a = rotacaoEsquerdaDireitaAluno(a);
  // Rotação dupla à direita.
  else if(fb < -1 && fatorDeBalanceamentoAluno(a->direito) > 0)
    a = rotacaoDireitaEsquerdaAluno(a);
  return a;
}

// Função que adiciona um novo aluno.
stc_Aluno* novoAluno(char id[], char nome[], char cpf[]){
  stc_Aluno *novo = malloc(sizeof(stc_Aluno));
  if(novo){
    strcpy(novo->id,id);
    strcpy(novo->nome,nome);
    strcpy(novo->cpf,cpf);
    novo->esquerdo = NULL;
    novo->direito = NULL;
    novo->altura = 0;
  }
  else
    printf("\nErro ao adicionar novo aluno\n");
  return novo;
}

// Função que adiciona um aluno.
stc_Aluno* adicionaAluno(stc_Aluno *a, char id[], char nome[], char cpf[]){
  if(a == NULL) 
    return novoAluno(id, nome, cpf);
  else{ 
    if(atof(id) < atof(a->id))
      a->esquerdo = adicionaAluno(a->esquerdo, id, nome, cpf);
    else if(atof(id) > atof(a->id))
      a->direito = adicionaAluno(a->direito, id, nome, cpf);
  }
  // Recalcula a altura de todos os nós entre a raiz e o novo nó inserido.
  a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
  // Verifica a necessidade de rebalancear a árvore.
  a = balancearAluno(a);
  return a;
}

// Função que remove um aluno pelo ID ou CPF.
stc_Aluno* removeAluno(stc_Aluno *a, char variavel[], int opcao){
  if(a == NULL){
    if(strlen(variavel) == (CAID-1)){
      printf("\nO ID digitado não existe no banco de dados\n");
      return NULL;
    }
  } 
  else{ 
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(a->id, variavel) == 0){
        if(a->esquerdo == NULL && a->direito == NULL){
          if(opcao)
            printf("\nAluno removido com sucesso\n");
          free(a);
          return NULL;
        }
        else{
          if(a->esquerdo != NULL && a->direito != NULL){
            stc_Aluno *aux = a->esquerdo;
            while(aux->direito != NULL)
              aux = aux->direito;
            strcpy(a->id, aux->id);
            strcpy(aux->id, variavel);
            strcpy(a->nome, aux->nome);
            strcpy(a->cpf, aux->cpf);
            a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
            return a;
          }
          else{
            stc_Aluno *aux;
            if(a->esquerdo != NULL)
              aux = a->esquerdo;
            else
              aux = a->direito;
            if(opcao)
              printf("\nAluno removido com sucesso\n");
            free(a);
            return aux;
          }
        }
      }
      else{
        if(atof(variavel) < atof(a->id))
          a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
        else
          a->direito = removeAluno(a->direito, variavel, opcao);
      }
    }  
    else if(strlen(variavel) == (CACPF-1)){
      if(strcmp(a->cpf, variavel) == 0){
        if(a->esquerdo == NULL && a->direito == NULL){
          if(opcao)
            printf("\nAluno removido com sucesso\n");
          free(a);
          return NULL;
        }
        else{
          if(a->esquerdo != NULL && a->direito != NULL){
            stc_Aluno *aux = a->esquerdo;
            while(aux->direito != NULL)
              aux = aux->direito;
            strcpy(a->cpf, aux->cpf);
            strcpy(aux->cpf, variavel);
            strcpy(a->nome, aux->nome);
            strcpy(a->id, aux->id);
            a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
            return a;
          }
          else{
            stc_Aluno *aux;
            if(a->esquerdo != NULL)
              aux = a->esquerdo;
            else
              aux = a->direito;
            if(opcao)
              printf("\nAluno removido com sucesso\n");
            free(a);
            return aux;
          }
        }
      }
      else{
        a->esquerdo = removeAluno(a->esquerdo, variavel, opcao);
        a->direito = removeAluno(a->direito, variavel, opcao);
      }
    }
    // Recalcula a altura de todos os nós entre a raiz e o novo nó inserido.
    a->altura = maior(alturaAluno(a->esquerdo), alturaAluno(a->direito)) + 1;
    // Verifica a necessidade de rebalancear a árvore.
    a = balancearAluno(a);
    return a;
  }
  return a;
}

// Função para imprimir dados.
int imprimeAluno(int i, char variavel[]){
  FILE *arq_aluno;
  stc_Aluno aluno;
  arq_aluno = fopen("aluno.bin","a+b");
  printf("\t\t\t\t\t\t  LISTA DE ALUNOS\n");
  printf("\t-----------------------------------------------------------\n");
  printf("\t|\t ID\t\t| \t  CPF\t  | \t\t\t NOME\t\t\t  |\n");
  printf("\t-----------------------------------------------------------\n");
  while(fread(&aluno, 1, sizeof(stc_Aluno), arq_aluno) > 0){
    if(i == 1){
      if(strcmp(aluno.id, variavel) == 0){
        printf("\t%s | %s | %s \n", aluno.id, aluno.cpf, aluno.nome);
        printf("\t-----------------------------------------------------------\n\n");
        return 1;
      }
    }
    else
      printf("\t%s | %s | %s \n", aluno.id, aluno.cpf, aluno.nome);
  }
  printf("\t-----------------------------------------------------------\n\n");
  return 1;
}

// Função para salvar os dados no arquivo.
void salvarAluno(stc_Aluno **a){
  FILE *arq_aluno;
  stc_Aluno aluno;
  int temp;
  if(*a!=NULL){
    salvarAluno(&(*a)->esquerdo);
    arq_aluno = fopen("aluno.bin","a+b");
    strcpy(aluno.id, (*a)->id);
    strcpy(aluno.nome, (*a)->nome);
    strcpy(aluno.cpf, (*a)->cpf);
    temp = fwrite(&aluno, 1, sizeof(stc_Aluno), arq_aluno);
    if (!temp)
      printf ("Erro ao salvar\n");
    fclose(arq_aluno);
    salvarAluno(&(*a)->direito);
  }
}

// Função para procurar um aluno pelo ID, NOME ou CPF.
int procureAluno(stc_Aluno **a, char variavel[]){
  if(*a != NULL){
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(variavel, (*a)->id) == 0){
        printf("\nID: %s\nNome: %s\nCPF: %s\n\n", (*a)->id, (*a)->nome, (*a)->cpf);
      }
      else if(atof(variavel) < atof((*a)->id))
        return procureAluno(&(*a)->esquerdo, variavel);
      else if(atof(variavel) > atof((*a)->id))
        return procureAluno(&(*a)->direito, variavel);
    }
    else if(strlen(variavel) <= (CANOME-1)){
      procureAluno(&(*a)->esquerdo, variavel);
      procureAluno(&(*a)->direito, variavel);
      if(strcmp(variavel, (*a)->nome) == 0)
        printf("\nID: %s\nNome: %s\nCPF: %s\n\n", (*a)->id, (*a)->nome, (*a)->cpf);
    }  
    else if(strlen(variavel) == (CACPF-1)){
      procureAluno(&(*a)->esquerdo, variavel);
      procureAluno(&(*a)->direito, variavel);
      if(strcmp(variavel, (*a)->cpf) == 0)
        printf("\nID: %s\nNome: %s\nCPF: %s\n\n", (*a)->id, (*a)->nome, (*a)->cpf);
    }
  return 1;
  }
  else
    return 0;
}

// Verifica se o ID, NOME ou CPF digitado existe no banco de dados.
int compareAluno(stc_Aluno **a, char variavel[]){
  int i, j, aux = 0; 
  if(*a != NULL){
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(variavel, (*a)->id) == 0)
        return 1;
      else if(atof(variavel) < atof((*a)->id))
        i = compareAluno(&(*a)->esquerdo, variavel);
      else if(atof(variavel) > atof((*a)->id))
        j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(strlen(variavel) <= (CANOME-1)){
      if(strcmp(variavel, (*a)->nome) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel);
      int j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(strlen(variavel) == (CACPF-1)){
      if(strcmp((*a)->cpf, variavel) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel);
      int j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
  }
  else{
    if(aux == 1)
      return aux;
  }
  return aux;
}

// Guarda em uma variável o ID digitado.
char* idAluno(stc_Aluno *a, int opcao){
  stc_Aluno aluno;
  int b, c, d, e;
  char *dado = malloc(sizeof(char)*CAID);
  if(opcao == 1){
    // Recebe conteúdo ID.
    printf("\nDigite o ID do aluno (%d dígitos): ", CAID-1);
    scanf(" %s", aluno.id);
    // Verifica se o ID possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.id[b] != '\0'; b++){
      if(!isdigit(aluno.id[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o ID possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.id[b] != '\0'; b++)
      d++;
    e = compareAluno(&a, aluno.id);
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != (CAID-1) || e == 1){
      e = compareAluno(&a, aluno.id);
      if(e == 1)
        printf("\nEste ID já está em uso\n");
      printf("\nID inválido, digite novamente\n");
      printf("\nID (%d dígitos): ", CAID-1);
      scanf(" %s", aluno.id);
      c = 0;
      d = 0;
      for( b = 0; aluno.id[b] != '\0'; b++){
        if(!isdigit(aluno.id[b])){
          c = 1;
          break;
        }
      }
      for( b = 0; aluno.id[b] != '\0'; b++)
        d++;
      e = compareAluno(&a, aluno.id);
    }
  }
  else if(opcao == 2){
    // Recebe conteúdo ID.
    printf("Digite o ID do aluno (%d dígitos): ", CAID-1);
    scanf(" %s", aluno.id);
    // Verifica se o ID possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.id[b] != '\0'; b++){
      if(!isdigit(aluno.id[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o ID possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.id[b] != '\0'; b++)
      d++;
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != (CAID-1)){
      printf("\nID inválido, digite novamente\n");
      printf("\nID (%d dígitos): ", CAID-1);
      scanf(" %s", aluno.id);
      c = 0;
      d = 0;
      for( b = 0; aluno.id[b] != '\0'; b++){
        if(!isdigit(aluno.id[b])){
          c = 1;
          break;
        } 
      }
      for( b = 0; aluno.id[b] != '\0'; b++)
        d++;
    }
  }
  strcpy(dado, aluno.id);
  return dado;
}

// Guarda em uma variável o NOME digitado.
char* nomeAluno(stc_Aluno *a){
  stc_Aluno aluno;
  int b, c, d;
  char *dado = malloc(sizeof(char)*CANOME);
  // Recebe conteúdo NOME.
  printf("Digite o NOME do aluno (%d dígitos): ", CANOME-1);
  scanf(" %[^\n]s", aluno.nome);
  // Verifica se o NOME possui quantidade correta de caracteres.
  c = 0;
  for( b = 0; aluno.nome[b] != '\0'; b++){
    if(!islower(aluno.nome[b]))
      if(!isupper(aluno.nome[b])){
        if(!isspace(aluno.nome[b])){
          c = 1;
          break;
        }
      }
  }
  // Verifica se o NOME possui quantidade correta de caracteres.
  d = 0;
  for( b = 0; aluno.nome[b] != '\0'; b++)
    d++;
  // Repete a pergunta no caso de dado inválido.
  while(c == 1 || d > (CANOME-1)){
    printf("\nNOME inválido, digite novamente\n");
    printf("\nNome (%d dígitos): ", CANOME-1);
    scanf(" %[^\n]s", aluno.nome);
    c = 0;
    d = 0;
    for( b = 0; aluno.nome[b] != '\0'; b++){
      if(!islower(aluno.nome[b]))
        if(!isupper(aluno.nome[b])){
          if(!isspace(aluno.nome[b])){
            c = 1;
            break;
          }
        }
    }
    for( b = 0; aluno.nome[b] != '\0'; b++)
      d++;
  }
  strcpy(dado, aluno.nome);
  return dado;
}

// Guarda em uma variável o CPF digitado.
char* cpfAluno(stc_Aluno *a, int opcao){
  stc_Aluno aluno;
  int b, c, d, e;
  char *dado = malloc(sizeof(char)*CACPF);
  if(opcao == 1){
    // Recebe conteúdo CPF.
    printf("Digite o CPF do aluno (%d dígitos): ", CACPF-1);
    scanf(" %s", aluno.cpf);
    // Verifica se o CPF possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++){
      if(!isdigit(aluno.cpf[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o CPF possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++)
      d++;
    e = compareAluno(&a, aluno.cpf);
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != (CACPF-1) || e == 1){
      e = compareAluno(&a, aluno.cpf);
      if(e == 1)
        printf("\nEste CPF já está em uso\n");
      printf("\nCPF inválido, digite novamente\n");
      printf("\nCPF (%d dígitos): ", CACPF-1);
      scanf(" %s", aluno.cpf);
      c = 0;
      d = 0;
      for( b = 0; aluno.cpf[b] != '\0'; b++){
        if(!isdigit(aluno.cpf[b])){
          c = 1;
          break;
        }
      }
      for( b = 0; aluno.cpf[b] != '\0'; b++)
        d++;
      e = compareAluno(&a, aluno.cpf);
    }
  }
  else if(opcao == 2){
    // Recebe conteúdo CPF.
    printf("Digite o CPF do aluno (%d dígitos): ", CACPF-1);
    scanf(" %s", aluno.cpf);
    // Verifica se o CPF possui caracteres válidos.
    c = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++){
      if(!isdigit(aluno.cpf[b])){
        c = 1;
        break;
      }
    }
    // Verifica se o CPF possui quantidade correta de caracteres.
    d = 0;
    for( b = 0; aluno.cpf[b] != '\0'; b++)
      d++;
    // Repete a pergunta no caso de dado inválido.
    while(c == 1 || d != CACPF-1){
      printf("\nCPF inválido, digite novamente\n");
      c = CACPF-1;
      printf("\nCPF (%d dígitos): ", c);
      scanf(" %s", aluno.cpf);
      c = 0;
      d = 0;
      for( b = 0; aluno.cpf[b] != '\0'; b++){
        if(!isdigit(aluno.cpf[b])){
          c = 1;
          break;
        }
      }
      for( b = 0; aluno.cpf[b] != '\0'; b++)
        d++;
    }
  }
  strcpy(dado, aluno.cpf);
  return dado;
}

// Altera um dado do aluno que o usuário escolher pelo seu ID.
stc_Aluno* alteraAluno(stc_Aluno **a, stc_Aluno **A, char variavel[], int opcao){
  char id[CAID], nome[CANOME], cpf[CACPF];
  if(*a != NULL){
    if(opcao == 1){
      if(strcmp(variavel, (*a)->id) == 0){
        strcpy(nome, (*a)->nome);
        strcpy(cpf, (*a)->cpf);
        strcpy(id, idAluno(*A, 1));
        *A = removeAluno(*A, (*a)->id, 0);
        *A = adicionaAluno(*A, id, nome, cpf);
        remove("aluno.bin");
        salvarAluno(&(*A));
        printf("\nID salvo com sucesso\n");
      }
      else if(atof(variavel) < atof((*a)->id))
        alteraAluno(&(*a)->esquerdo, &(*A), variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        alteraAluno(&(*a)->direito, &(*A), variavel, opcao);
    }
    else if(opcao == 2){
      if(strcmp(variavel, (*a)->id) == 0){
        strcpy((*a)->nome, nomeAluno(*A));
        remove("aluno.bin");
        salvarAluno(&(*A));
        printf("\nNOME salvo com sucesso\n");
      }
      else if(atof(variavel) < atof((*a)->id))
        alteraAluno(&(*a)->esquerdo, &(*A), variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        alteraAluno(&(*a)->direito, &(*A), variavel, opcao);
    }
    else if(opcao == 3){
      if(strcmp(variavel, (*a)->id) == 0){
        strcpy((*a)->cpf, cpfAluno(*A, 1));
        remove("aluno.bin");
        salvarAluno(&(*A));
        printf("\nCPF salvo com sucesso\n");
      }
      else if(atof(variavel) < atof((*a)->id))
        alteraAluno(&(*a)->esquerdo, &(*A), variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        alteraAluno(&(*a)->direito, &(*A), variavel, opcao);
    }
  }
  return *A;
}
  

int main(void) 
{
  FILE *arq_aluno, *arq_curso, *arq_alunoCurso;
  stc_Aluno aluno, *student = NULL;
  int a;
  char b;

  arq_aluno = fopen("aluno.bin","rb");
  if(!arq_aluno)
    printf("\nErro na abertura do arquivo da tabela ALUNO\nAdicione um aluno!\n");
  else{
    while(fread(&aluno,1,sizeof(stc_Aluno),arq_aluno) > 0)
      // Readiciona os dados na AVL.
      student = adicionaAluno(student, aluno.id, aluno.nome, aluno.cpf);
  }
    
  arq_curso = fopen("curso.bin","rb");
  if(!arq_curso)
    printf("\nErro na abertura do arquivo da tabela CURSO\nAdicione um curso!\n");
  
  arq_alunoCurso = fopen("alunoCurso.bin","rb");
  if(!arq_alunoCurso)
    printf("\nErro na abertura do arquivo da tabela ALUNO_CURSO\nAdicione um curso e um aluno!\n");

  do{
    fprintf(stdout, "\nDeseja usar qual tabela?\n\n1-tbl_aluno\n2-tbl_curso\n3-tbl_alunocurso\n\nR : ");
    fscanf(stdin, "%d", &a);
    printf("\n");
    switch(a)
    {
      // Funcionalidades para a tabela aluno.
      case 1:
        do{
          fprintf(stdout, "\nO que você deseja fazer na tabela ALUNO?\n\n1-Adicionar aluno\n2-Procurar aluno\n3-Remover aluno\n4-Alterar informação do aluno\n5-Imprimir alunos\n6-Voltar\n\nR : ");
          fscanf(stdin, "%d", &a);
          printf("\n");
          switch(a)
          {
            case 1: 
              do{
                strcpy(aluno.id, idAluno(student, 1));
                strcpy(aluno.nome, nomeAluno(student));
                strcpy(aluno.cpf, cpfAluno(student, 1));
                // Adiciona os dados na AVL.
                student = adicionaAluno(student, aluno.id, aluno.nome, aluno.cpf);
                remove("aluno.bin");
                salvarAluno(&student);
                printf("\nAluno salvo com sucesso\n\n");
                printf("\nGostaria de adicionar outro aluno?\n\n1 SIM\t\t2 NÃO\n\nR : ");
                scanf(" %c", &b);
                printf("\n");
              }while(b == '1');
              break;

            case 2:
              do{
                fprintf(stdout, "\nComo você deseja procurar o aluno?\n\n1-ID\n2-Nome\n3-CPF\n4-Voltar\n\nR : ");
                fscanf(stdin, "%d", &a);
                printf("\n");
                switch(a)
                {
                  case 1: 
                    strcpy(aluno.id, idAluno(student, 2));
                    // Procura os dados relacionados ao ID digitado.
                    if(procureAluno(&student, aluno.id) != 1)
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;

                  case 2:
                    strcpy(aluno.nome, nomeAluno(student));
                    // Procura os dados relacionados ao NOME digitado.
                    if(compareAluno(&student, aluno.nome) == 1)
                      procureAluno(&student, aluno.nome);
                    else
                      printf("\nO NOME digitado não existe no banco de dados\n\n");
                    break;

                  case 3:
                    strcpy(aluno.cpf, cpfAluno(student, 2));
                    // Procura os dados relacionados ao CPF digitado.
                    if(compareAluno(&student, aluno.cpf) == 1)
                      procureAluno(&student, aluno.cpf);
                    else
                      printf("\nO CPF digitado não existe no banco de dados\n\n");
                    break;

                  case 4:
                    b = '2';
                    break;

                  default:
                    printf("Opção inválida\n\n");
                    a = 1;
                  
                }
              }while( a == 1 || a == 2 || a == 3 );
              break; 

            case 3:
              do{
                fprintf(stdout, "\nComo você deseja remover o aluno?\n\n1-ID\n2-CPF\n3-Voltar\n\nR : ");
                fscanf(stdin, "%d", &a);
                switch(a)
                {
                  case 1:
                    printf("\n");
                    imprimeAluno(0, NULL);
                    printf("\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    student = removeAluno(student, aluno.id, 1);
                    remove("aluno.bin");
                    salvarAluno(&student);
                    printf("\n");
                    b = 'X';
                    break;

                  case 2:
                    printf("\n");
                    imprimeAluno(0, NULL);
                    printf("\n");
                    strcpy(aluno.cpf, cpfAluno(student, 2));
                    if(compareAluno(&student, aluno.cpf) == 1){
                      student = removeAluno(student, aluno.cpf, 1);
                      remove("aluno.bin");
                      salvarAluno(&student);
                      printf("\n");
                    }
                    else
                      printf("\nO CPF digitado não existe no banco de dados\n\n");
                    b = '2';
                    break;

                  case 3:
                    b = '2';
                    printf("\n");
                    break;

                  default:
                    printf("\nOpção inválida\n\n");
                    a = 1;
                    
                }
              }while( a == 1 || a == 2 );
              break;

            case 4:
              do{
                fprintf(stdout, "\nQual informação você deseja alterar do aluno?\n\n1-ID\n2-Nome\n3-CPF\n4-Voltar\n\nR : ");
                fscanf(stdin, "%d", &a);
                printf("\n");
                switch(a)
                {
                  case 1: 
                    printf("ID que deseja alterar\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    printf("\n\n");
                    imprimeAluno(1, aluno.id);
                    if(compareAluno(&student, aluno.id) == 1){
                      printf("\nNovo ID do aluno");
                      student = alteraAluno(&student, &student, aluno.id, 1);
                      printf("\n");
                    }
                    else
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;

                  case 2:
                    printf("ID do aluno que deseja alterar o nome\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    printf("\n\n");
                    imprimeAluno(1, aluno.id);
                    if(compareAluno(&student, aluno.id) == 1){
                      printf("\nNovo NOME do aluno\n");
                      student = alteraAluno(&student, &student, aluno.id, 2);
                      printf("\n");
                    }
                    else
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;

                  case 3:
                    printf("ID do aluno que deseja alterar o cpf\n");
                    strcpy(aluno.id, idAluno(student, 2));
                    printf("\n\n");
                    imprimeAluno(1, aluno.id);
                    if(compareAluno(&student, aluno.id) == 1){
                      printf("\nNovo CPF do aluno\n");
                      student = alteraAluno(&student, &student, aluno.id, 3);
                      printf("\n");
                    }
                    else
                      printf("\nO ID digitado não existe no banco de dados\n\n");
                    break;
                  
                  case 4:
                    b = '2';
                    break;

                  default:
                    printf("Opção inválida\n\n");
                    a = 1;
                  
                }
              }while( a == 1 || a == 2 || a == 3 );
              break;

            case 5:
              imprimeAluno(0, NULL);
              b = '2';
              break;

            case 6:
              b = 0;
              a = 1;
              break;

            default:
              printf("Opção inválida\n\n");
              b = '2';
          }
        }while(b == '2');

      // Funcionalidades para a tabela curso.
      case 2:
        break;

      case 3:
        break;

      default:
        printf("Opção inválida\n\n");
        a = 1;
      
    }
  }while( a == 1 || a == 2 || a == 3 );
  
  return 0;
}
  

 

 

O simples. Depois vou ver o código. 

Se você posta o cõdigo todo mundo pode ler, aprender algo ou copiar. Se você posta um quadradinho escrito "codigo.txt"  não é nada parecido

 

Compreendi agora, para mim colocar o código todo aqui no site (ainda mais com tantas linhas) seria tipo uma "poluição do post". Obrigado novamente.

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

@donutLukke Entendo o que quer dizer, mas o site já faz a redução do bloco de código ao ler e mostra só as primeiras linhas. E quem tiver interesse em ler ou ajudar pode usar a barra de rolagem. E não é preciso sair do site. Devia ter uma opção no forum para acrescentar números de linha eu acho, para facilitar a referência. E Um botão para copiar o código  --- sem os números de linha, claro --- como tem por exemplo na documentação da Microsoft

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

2 horas atrás, arfneto disse:

Algo como isso --- de https://learn.microsoft.com/pt-br/windows/win32/procthread/creating-processes por exemplo --- seria muito bom no forum

 

image.thumb.png.bd987c7d62b7993beaf6efefcd4ef15e.png

 

Mas com um outro botão para acrescentar os números de linha para referência 🙂 

 

Você rodou o código que mandei e fez o exemplos que tem nas imagens? Consegue dar um panorama do que possa estar acontecendo?

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

48 minutos atrás, arfneto disse:

 

Ainda não tive tempo. Mas vou ver sim.

 

Muito obrigado.

56 minutos atrás, arfneto disse:

 

Ainda não tive tempo. Mas vou ver sim.

 

Uma pessoa aparentemente encontrou o problema, na função "compareAluno" a condição para procurar pelo ID, NOME ou CPF é o tamanho da string, como na condição que verifica o NOME há um "<=", sempre que eu colocar um número >= 12 (que é o tamanho da string do CPF), o código não passará na condição do CPF. Vou dar uma formulada no código, se conseguir resolver encerro o tópico.

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

  • Solução

Consegui encontrar o erro, a invasão de memória deve ter ocorrido por falha do compilador ou do buffer, como disse anteriormente, o erro estava na função "compareAluno", as condições colocadas estavam dando conflito por causa da seguinte condição "else if(strlen(variavel) <= (CANOME-1))", dessa forma, ao cair uma string de tamanho igual ou maior que "char cpf[CACPF]" , o código fazia a comparação da string "cpf" digitada com a string "nome" já adicionada.

 

Forma errada do código:

int compareAluno(stc_Aluno **a, char variavel[]){
  int i, j, aux = 0;
  if(*a != NULL){
    if(strlen(variavel) == (CAID-1)){
      if(strcmp(variavel, (*a)->id) == 0)
        return 1;
      else if(atof(variavel) < atof((*a)->id))
        i = compareAluno(&(*a)->esquerdo, variavel);
      else if(atof(variavel) > atof((*a)->id))
        j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(strlen(variavel) <= (CANOME-1)){ // erro nesta linha
      if(strcmp(variavel, (*a)->nome) == 0){
        return 1;
      }
      int i = compareAluno(&(*a)->esquerdo, variavel);
      int j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(strlen(variavel) == (CACPF-1)){
      if(strcmp(variavel, (*a)->cpf) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel);
      int j = compareAluno(&(*a)->direito, variavel);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
  }
  else{
    if(aux == 1)
      return aux;
  }
  return aux;
}

 

Forma correta do código:

int compareAluno(stc_Aluno **a, char variavel[], int opcao){
  int i, j, aux = 0; 
  if(*a != NULL){
    if(opcao == 1){
      if(strcmp(variavel, (*a)->id) == 0)
        return 1;
      else if(atof(variavel) < atof((*a)->id))
        i = compareAluno(&(*a)->esquerdo, variavel, opcao);
      else if(atof(variavel) > atof((*a)->id))
        j = compareAluno(&(*a)->direito, variavel, opcao);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(opcao == 2){
      if(strcmp(variavel, (*a)->nome) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel, opcao);
      int j = compareAluno(&(*a)->direito, variavel, opcao);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
    else if(opcao == 3){
      if(strcmp((*a)->cpf, variavel) == 0)
        return 1;
      int i = compareAluno(&(*a)->esquerdo, variavel, opcao);
      int j = compareAluno(&(*a)->direito, variavel, opcao);
      if(i == 1)
        return aux = 1;
      else if(j == 1)
        return aux = 1;
      else
        return 0;
    }
  }
  else{
    if(aux == 1)
      return aux;
  }
  return aux;
}

 

Desde já, agradeço pelo aprendizado de como formular um tópico seguindo as diretrizes do fórum para explicitar minha dúvida.

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

Parece que resolveu esse problema, mas agora a função tem um argumento a mais e não postou o código que usa isso e nem descreveu o que são esses parâmetros, então não dá pra entender ou julgar nada. Talvez devesse postar o código modificado.

 

De qualquer forma: lendo o programa o que posso dizer é que está indo por um caminho incrivelmente complicado. E também está misturando lógica do programa com a formatação e leitura e abstração de dados (a tal árvore) com o Aluno. Isso leva a uma confusão enorme e uma dificuldade imensa pra testar. Sugiro rever essas coisas e reescrever em torno dos dados.

 

Não há qualquer descrição do objetivo ou enunciado e fica difícil de julgar essa parte. O que é stc_AlunoCurso? por exemplo?

 

Se é um arquivo que vincula os alunos aos cursos e vice versa, como um modelo ER, tem uma duplicidade do inferno nisso porque vai repetir aluno e curso para TODAS as ocorrências de Aluno em um curso.

 

Provavelmente não é isso que quer. Se precisa dos dois relacionamentos o mais comum é ter

  • um vetor de árvores AVL com uma ocorrência para cada curso. Assim fica trivial listar os alunos matriculados em cada curso.
  • um ponteiro na estrutura do aluno para uma lista de cursos do cara. Não precisaria ser uma árvore porque o total de cursos é no mundo real tão pequeno que uma estrutura de dados seria exagero, com mais ponteiros que dados.

Sobre o código

  • A árvore é de nós e não de alunos ou cursos ou qualquer coisa. Se escrever assim poderá usar seu código para a árvore em qualquer programa. E é isso o que se quer. a AVL é uma coleção de nós. Eles podem ser qualquer coisa. Escreva assim e fará isso poucas vezes na vida...
  • Não por acaso as 3 estruturas são parecidas: são a mesma
  • short alturaAluno(stc_Aluno* a) não existe, porque é a mesma coisa para ALuno, Curso, Professor, Musica...
  • não use acentos em comentários. De nada servem e muitas vezes não saem direito na tela ou na impressora
  • evite os comentários /**/ e prefira sempre //
  • NUNCA escreva um programa interativo. Só vai perder tempo.
  • parece que vai acabar escrevendo 3 conjuntos de funções iguais para Aluno, Curso e CursoAluno, e elas serão a mesma....
  • nunca use um menu em um programa que não está pronto. Melhor: NUNCA escreva um programa interativo. Nada vai aprender e só vai perder tempo. Muito tempo. Coloque isso depois.
  • Se seu programa tem um menu escreva uma função que mostra as opções e retorna a opção
  • main() deve ser a primeira função de seu programa. Se possível em um arquivo separado. SEMPRE
  • rotações como stc_Aluno* rotacaoEsquerdaAluno(stc_Aluno* a) nada tem a ver com aluno. Só com a árvore. Coo misturou as coisas não vai te servir de nada em outra árvore.
  • Não tem sentido balancear um aluno ou um curso.
  • coisas como
     
    stc_Aluno* novoAluno(char id[], char nome[], char cpf[])
    {
        stc_Aluno* novo = malloc(sizeof(stc_Aluno));
        if (novo)
        {
            strcpy(novo->id, id);
            strcpy(novo->nome, nome);
            strcpy(novo->cpf, cpf);
            novo->esquerdo = NULL;
            novo->direito  = NULL;
            novo->altura   = 0;
        }
        else
            printf("\nErro ao adicionar novo aluno\n");
        return novo;
    }

são comuns mas tem pouco sentido. Escreva o simples, o óbvio e retorne assim que possível. Se malloc() falhar vai retornar NULL então deveria ter escrito
 

stc_Aluno* novoAluno(char id[], char nome[], char cpf[])
{
    stc_Aluno* novo = malloc(sizeof(stc_Aluno));
    if (novo == NULL)
    {
        printf("\nErro ao adicionar novo aluno\n");
        return NULL;
    }
    strcpy(novo->id, id);
    strcpy(novo->nome, nome);
    strcpy(novo->cpf, cpf);
    novo->esquerdo = NULL;
    novo->direito  = NULL;
    novo->altura   = 0;
    return novo;
}

 

Mas entenda que se está inserindo o aluno em uma árvore o simples é escrever algo como

 

int adc_aluno( Aluno* al, AVL* avl_alunos);

 

E ter uma função que insere o nó na árvore e retorna zero se deu certo ou algo negativo com o código do erro.

 

Sobre isso

 

void salvarAluno(stc_Aluno** a)
{
    FILE*     arq_aluno;
    stc_Aluno aluno;
    int       temp;
    if (*a != NULL)
    {
        salvarAluno(&(*a)->esquerdo);
        arq_aluno = fopen("aluno.bin", "a+b");
        strcpy(aluno.id, (*a)->id);
        strcpy(aluno.nome, (*a)->nome);
        strcpy(aluno.cpf, (*a)->cpf);
        temp = (int)fwrite(
            &aluno, (size_t)1, sizeof(stc_Aluno),
            arq_aluno);
        if (!temp) printf("Erro ao salvar\n");
        fclose(arq_aluno);
        salvarAluno(&(*a)->direito);
    }
}

 

Para que usar stc_Aluno** se a função só usa (*a)? isso quer dizer que está errado e o argumento deveria ser apenas stc_Aluno*. Pense nisso.
Há sérias razões para usar char** X ou mesmo char**** ou até algo sinistro como char** ** ** X ou qualquer outro tipo para X. Mas isso tem que ser construído com cuidado e pode e dá muito erro. Para um exemplo: um arquivo csv pode ser colocado inteiro em algo como char** ** meu_csv. Mas é algo sério e deve ser construído com cuidado. FUJA disso.

 

Isso seria a mesma coisa:

 

void salvarAluno(stc_Aluno* a)
{
    FILE*     arq_aluno;
    stc_Aluno aluno;
    if (a != NULL)
    {
        salvarAluno(a->esquerdo);
        arq_aluno = fopen("aluno.bin", "a+b");
        strcpy(aluno.id, a->id);
        strcpy(aluno.nome, a->nome);
        strcpy(aluno.cpf, a->cpf);
        int temp = (int)fwrite(
            &aluno, 1, sizeof(stc_Aluno),
            arq_aluno);
        if (!temp) printf("Erro ao salvar\n");
        fclose(arq_aluno);
        salvarAluno(a->direito);
    }
}

 

E mais ainda NUNCA deixe ponteiros soltos pelo programa. Prefira 
 

        FILE* arq_aluno = fopen("aluno.bin", "a+b");

 

E sua estrutura Aluno é trivial, não tem ponteiros nem nada e  pode copiar os dados com uma só atribuição, usando

 

	stc_Aluno = a;

 

E pra que criar isso afinal se apenas vai gravar em disco? Isso poderia ter uma linha só. E porque chamar recursivamente isso? Vai mesmo funcionar? Vai ter um FILE* aberto para cada aluno na árvore até terminar e rodar um close ao final de cada chamada???

 

Cansei de escrever. Pense nisso.

 

E separe os códigos da árvore do resto do programa porque nada tem a ver uma coisa com a outra.

 

Veja

 

typedef struct A
{
    char      id[CAID];
    char      nome[CANOME];
    char      cpf[CACPF];
    struct A* esquerdo;
    struct A* direito;
    short     altura;
} stc_Aluno;

typedef struct C
{
    char      id[CCID];
    char      nome[CCNOME];
    char      departamento[5];
    int       creditos;
    struct C* esquerdo;
    struct C* direito;
    short     altura;
} stc_Curso;

 

São iguais porque são a mesma coisa.

 

Pense nessa composição

 

typedef struct st_AVL
{
    void*  info;
    struct st_AVL* esquerdo;
    struct st_AVL* direito;
    short  altura;
}   AVL;

typedef struct
{
    char      id[CAID];
    char      nome[CANOME];
    char      cpf[CACPF];
}   Aluno;

typedef struct 
{
    char      id[CCID];
    char      nome[CCNOME];
    char      departamento[5];
    int       creditos;
    AVL*      al; // alunos neste curso
}   Curso;

typedef struct
{
    unsigned ttl_cursos;
    AVL**    cursos;
}   Grade_Completa;

 

Não é um modelo completo e pode até estar errado, estou escrevendo sem pensar, mas:

  • tem uma abstração da arvore AVL
  • o ponteiro info pode ser Aluno* para a árvore de alunos ou Curso* ou Coisa*. Genérico. C foi escrita para isso
  • cada curso pode ter uma árvore com os alunos matriculados

a struct Grade_Completa tem um vetor de ponteiros e cada um aponta para uma árvore de Curso. Você pode representar todos os cursos na escola em manaus como

 

  • 	grade_Completa grd_Manaus = { 0, NULL };

 

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

Essas funções

 

// Guarda em uma variável o NOME digitado.
char* nomeAluno(stc_Aluno* a)

E

// Guarda em uma variável o CPF digitado.
char* cpfAluno(stc_Aluno* a, int opcao)

 

por exemplo, são a mesma e copiou uma da outra. Pra que isso? E parece que isso era pra inserir um nó na árvore! É isso mesmo? E já pensou em descrever nos comentários o que é uma possível opção? vai gostar disso daqui umas semanas quando não lembrar mais do programa e for mudar algo.

 

        for (b = 0; aluno.nome[b] != '\0'; b++) d++;

 

Evite esses loops. É melhor desconfiar. Sabe que o campo tem um limite. Esse é o fim do loop. USE. Se o campo estiver corrompido e faltar exatamente o NULL vai zoar tudo.

 

Nunca escreva um código interativo. Você só vai ter problemas aqui ao identificar um CPF ou Aluno inválido e simplesmente mostrar uma pergunta na tela. Não faça isso. Nunc. Uma função lê o campo.  cpfAluno retorna um status se o campo for inválido, ou NULL. Só isso.

 

 

 

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

Em 06/01/2023 às 02:18, arfneto disse:

Parece que resolveu esse problema, mas agora a função tem um argumento a mais e não postou o código que usa isso e nem descreveu o que são esses parâmetros, então não dá pra entender ou julgar nada. Talvez devesse postar o código modificado.

 

De qualquer forma: lendo o programa o que posso dizer é que está indo por um caminho incrivelmente complicado. E também está misturando lógica do programa com a formatação e leitura e abstração de dados (a tal árvore) com o Aluno. Isso leva a uma confusão enorme e uma dificuldade imensa pra testar. Sugiro rever essas coisas e reescrever em torno dos dados.

 

Não há qualquer descrição do objetivo ou enunciado e fica difícil de julgar essa parte. O que é stc_AlunoCurso? por exemplo?

 

Se é um arquivo que vincula os alunos aos cursos e vice versa, como um modelo ER, tem uma duplicidade do inferno nisso porque vai repetir aluno e curso para TODAS as ocorrências de Aluno em um curso.

 

Provavelmente não é isso que quer. Se precisa dos dois relacionamentos o mais comum é ter

  • um vetor de árvores AVL com uma ocorrência para cada curso. Assim fica trivial listar os alunos matriculados em cada curso.
  • um ponteiro na estrutura do aluno para uma lista de cursos do cara. Não precisaria ser uma árvore porque o total de cursos é no mundo real tão pequeno que uma estrutura de dados seria exagero, com mais ponteiros que dados.

Sobre o código

  • A árvore é de nós e não de alunos ou cursos ou qualquer coisa. Se escrever assim poderá usar seu código para a árvore em qualquer programa. E é isso o que se quer. a AVL é uma coleção de nós. Eles podem ser qualquer coisa. Escreva assim e fará isso poucas vezes na vida...
  • Não por acaso as 3 estruturas são parecidas: são a mesma
  • short alturaAluno(stc_Aluno* a) não existe, porque é a mesma coisa para ALuno, Curso, Professor, Musica...
  • não use acentos em comentários. De nada servem e muitas vezes não saem direito na tela ou na impressora
  • evite os comentários /**/ e prefira sempre //
  • NUNCA escreva um programa interativo. Só vai perder tempo.
  • parece que vai acabar escrevendo 3 conjuntos de funções iguais para Aluno, Curso e CursoAluno, e elas serão a mesma....
  • nunca use um menu em um programa que não está pronto. Melhor: NUNCA escreva um programa interativo. Nada vai aprender e só vai perder tempo. Muito tempo. Coloque isso depois.
  • Se seu programa tem um menu escreva uma função que mostra as opções e retorna a opção
  • main() deve ser a primeira função de seu programa. Se possível em um arquivo separado. SEMPRE
  • rotações como stc_Aluno* rotacaoEsquerdaAluno(stc_Aluno* a) nada tem a ver com aluno. Só com a árvore. Coo misturou as coisas não vai te servir de nada em outra árvore.
  • Não tem sentido balancear um aluno ou um curso.
  • coisas como
     
    stc_Aluno* novoAluno(char id[], char nome[], char cpf[])
    {
        stc_Aluno* novo = malloc(sizeof(stc_Aluno));
        if (novo)
        {
            strcpy(novo->id, id);
            strcpy(novo->nome, nome);
            strcpy(novo->cpf, cpf);
            novo->esquerdo = NULL;
            novo->direito  = NULL;
            novo->altura   = 0;
        }
        else
            printf("\nErro ao adicionar novo aluno\n");
        return novo;
    }

são comuns mas tem pouco sentido. Escreva o simples, o óbvio e retorne assim que possível. Se malloc() falhar vai retornar NULL então deveria ter escrito
 

stc_Aluno* novoAluno(char id[], char nome[], char cpf[])
{
    stc_Aluno* novo = malloc(sizeof(stc_Aluno));
    if (novo == NULL)
    {
        printf("\nErro ao adicionar novo aluno\n");
        return NULL;
    }
    strcpy(novo->id, id);
    strcpy(novo->nome, nome);
    strcpy(novo->cpf, cpf);
    novo->esquerdo = NULL;
    novo->direito  = NULL;
    novo->altura   = 0;
    return novo;
}

 

Mas entenda que se está inserindo o aluno em uma árvore o simples é escrever algo como

 

int adc_aluno( Aluno* al, AVL* avl_alunos);

 

E ter uma função que insere o nó na árvore e retorna zero se deu certo ou algo negativo com o código do erro.

 

Sobre isso

 

void salvarAluno(stc_Aluno** a)
{
    FILE*     arq_aluno;
    stc_Aluno aluno;
    int       temp;
    if (*a != NULL)
    {
        salvarAluno(&(*a)->esquerdo);
        arq_aluno = fopen("aluno.bin", "a+b");
        strcpy(aluno.id, (*a)->id);
        strcpy(aluno.nome, (*a)->nome);
        strcpy(aluno.cpf, (*a)->cpf);
        temp = (int)fwrite(
            &aluno, (size_t)1, sizeof(stc_Aluno),
            arq_aluno);
        if (!temp) printf("Erro ao salvar\n");
        fclose(arq_aluno);
        salvarAluno(&(*a)->direito);
    }
}

 

Para que usar stc_Aluno** se a função só usa (*a)? isso quer dizer que está errado e o argumento deveria ser apenas stc_Aluno*. Pense nisso.
Há sérias razões para usar char** X ou mesmo char**** ou até algo sinistro como char** ** ** X ou qualquer outro tipo para X. Mas isso tem que ser construído com cuidado e pode e dá muito erro. Para um exemplo: um arquivo csv pode ser colocado inteiro em algo como char** ** meu_csv. Mas é algo sério e deve ser construído com cuidado. FUJA disso.

 

Isso seria a mesma coisa:

 

void salvarAluno(stc_Aluno* a)
{
    FILE*     arq_aluno;
    stc_Aluno aluno;
    if (a != NULL)
    {
        salvarAluno(a->esquerdo);
        arq_aluno = fopen("aluno.bin", "a+b");
        strcpy(aluno.id, a->id);
        strcpy(aluno.nome, a->nome);
        strcpy(aluno.cpf, a->cpf);
        int temp = (int)fwrite(
            &aluno, 1, sizeof(stc_Aluno),
            arq_aluno);
        if (!temp) printf("Erro ao salvar\n");
        fclose(arq_aluno);
        salvarAluno(a->direito);
    }
}

 

E mais ainda NUNCA deixe ponteiros soltos pelo programa. Prefira 
 

        FILE* arq_aluno = fopen("aluno.bin", "a+b");

 

E sua estrutura Aluno é trivial, não tem ponteiros nem nada e  pode copiar os dados com uma só atribuição, usando

 

	stc_Aluno = a;

 

E pra que criar isso afinal se apenas vai gravar em disco? Isso poderia ter uma linha só. E porque chamar recursivamente isso? Vai mesmo funcionar? Vai ter um FILE* aberto para cada aluno na árvore até terminar e rodar um close ao final de cada chamada???

 

Cansei de escrever. Pense nisso.

 

E separe os códigos da árvore do resto do programa porque nada tem a ver uma coisa com a outra.

 

Veja

 

typedef struct A
{
    char      id[CAID];
    char      nome[CANOME];
    char      cpf[CACPF];
    struct A* esquerdo;
    struct A* direito;
    short     altura;
} stc_Aluno;

typedef struct C
{
    char      id[CCID];
    char      nome[CCNOME];
    char      departamento[5];
    int       creditos;
    struct C* esquerdo;
    struct C* direito;
    short     altura;
} stc_Curso;

 

São iguais porque são a mesma coisa.

 

Pense nessa composição

 

typedef struct st_AVL
{
    void*  info;
    struct st_AVL* esquerdo;
    struct st_AVL* direito;
    short  altura;
}   AVL;

typedef struct
{
    char      id[CAID];
    char      nome[CANOME];
    char      cpf[CACPF];
}   Aluno;

typedef struct 
{
    char      id[CCID];
    char      nome[CCNOME];
    char      departamento[5];
    int       creditos;
    AVL*      al; // alunos neste curso
}   Curso;

typedef struct
{
    unsigned ttl_cursos;
    AVL**    cursos;
}   Grade_Completa;

 

Não é um modelo completo e pode até estar errado, estou escrevendo sem pensar, mas:

  • tem uma abstração da arvore AVL
  • o ponteiro info pode ser Aluno* para a árvore de alunos ou Curso* ou Coisa*. Genérico. C foi escrita para isso
  • cada curso pode ter uma árvore com os alunos matriculados

a struct Grade_Completa tem um vetor de ponteiros e cada um aponta para uma árvore de Curso. Você pode representar todos os cursos na escola em manaus como

 

  • 	grade_Completa grd_Manaus = { 0, NULL };

 

 

Teria como você me explicar qual seria a função do void *info?

 

typedef struct st_AVL
{
    void*  info;
    struct st_AVL* esquerdo;
    struct st_AVL* direito;
    short  altura;
}   AVL;

 

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

@donutLukke Cara, uma árvore dessas é antes de tudo uma árvore. Binária. Tem um ponteiro pra esquerda e um pra direita. 

É um container, como se diz em C++, ou uma coleção, come se diz em C# ou java. Uma estrutura de dados.

 

E os dados?

 

Então tem uma árvore de coisas. De letrinhas, de músicas, de vagas no estacionamento, de registros no banco de dados, qualquer coisa. Mas ALGUMA coisa.

 

No seu caso a árvore contém estruturas de aluno:
 

typedef struct A
{
  char id[CAID];
  char nome[CANOME];
  char cpf[CACPF];
  struct A *esquerdo, *direito;
  short altura;
}stc_Aluno;

 

E esse é um dos problemas que seu programa original tinha. Está tudo misturado. id nome e tem a ver com o Aluno. O dado. Os ponteiros e a altura tem a ver com a árvore. Isso é MUITO ruim.

 

Que p. é void*?

 

Então no exemplo info é void*, um ponteiro para qualquer coisa. E assim pode usar esse código que trata árvore para qualquer coisa, qualquer árvore. E isso é importante. No futuro sua árvore pode não ser de Aluno. Seu código pode ser bom a ponto de você poder passar pra alguém, cobrar por ele por exemplo. Claro que não vai querer nenhuma referência ao dado lá dentro. Vai preferir algo genérico.

 

O que precisa para poder colocar na árvore alguma coisa?

 

Só precisa da noção de ordem. Tem que poder comparar um nó com outro, uma chave de acesso, qualquer coisa. Ou não vai saber o que vai pra esquerda ou pra direita na tal árvore. 

 

Então se a informação que sua árvore contém for um simples void* e você tiver uma função que compare dois desses void* pode usar seu código a vida toda sem ter que mexer em nada. Muitas vezes sem ter sequer que compilar essa parte. como fazer com printf() por exemplo. Só inclui stdio.h e usa printf() e outras. Então você colocaria seu código AVL em algo como AVLtree.h e já era.

 

void* é um ponteiro genérico. 

 

 

 

 

  • Obrigado 1
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!