sexta-feira, 29 de dezembro de 2017

Problema das operações sobre um vetor de structs


Compartilhe!

Neste programa em C abaixo, o objetivo é implementar funções de um programa que gerencia uma base de dados com registros acadêmicos de alunos contendo as seguintes informações para cada aluno:  RA, nome do aluno e telefone.

As operações que poderão ser realizadas sobre a base de dados são i) adição/edição de um aluno; ii) busca de um aluno; iii) remoção de um aluno; e iv) impressão de um registro. As funções para estas operações estão em um arquivo separado da função main. Neste laboratório, não há a necessidade de se preocupar com a entrada, apenas com a manipulação do vetor passado por parâmetro.

A base de dados é implementada com um vetor que é alocado dinamicamente.

O registro com as informações de um aluno deverá ser implementado como um struct.

Exemplo de entrada:

2
> 190029
+ 190029 99009912 Paulo da Silva
> 190029
+ 210419 91889912 Maria Souza
q

Exemplo de saída:

Base criada.
Aluno 190029 nao encontrado.
Adicionado: 190029 - 99009912 - Paulo da Silva
190029 - 99009912 - Paulo da Silva
Adicionado: 210419 - 91889912 - Maria Souza

Arquivo com a função main (autoria dos PEDs do IC-Unicamp):

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

typedef struct {
  int ra, telefone;
  char nome[100];
} Registro;
typedef struct {
  int armazenado;
  int capacidade;
  Registro *registros;
} Base;

void criar_base(Base *base, int n);
int buscar(Base *base, int ra);
void imprimir(Base *base, int ra);
void adicionar(Base *base, int ra, int telefone, char *nome);
void remover(Base *base, int ra);
void limpar(Base *base);
void liberar_base(Base *);

int main() {

  Base base;
  int capacidade;

  if (scanf("%d\n", &capacidade) != 1) {
    printf("Erro de Leitura da Capacidade\n");
    return 1;
  }
  criar_base(&base, capacidade);

  if (base.capacidade != capacidade) {
    printf("Capacidade inicial errada: %d\n", base.capacidade);
  }
  if (base.armazenado != 0) {
    printf("Quantidade armazenada inicial errada: %d\n", base.armazenado);
  }
  if (base.registros == NULL) {
    printf("Vetor de registros nao alocado.\n");
  }

  while (1) {
    char op;

    if (scanf("%s", &op) != 1) {
      break;
    } else if (op == 'q') {
      break;
    } else {
      int ra = 0;

      if (scanf("%d", &ra) != 1) {
        printf("Erro de Leitura do RA\n");
      }

      if (op == '>') {
        imprimir(&base, ra);
      } else if (op == '-') {
        remover(&base, ra);
      } else if (op == '+') {
        int telefone;
        char nome[100] = "";
        if (scanf(" %d %[^\n]", &telefone, nome) != 2) {
          printf("Erro de Leitura do telefone e nome.\n");
        }
        adicionar(&base, ra, telefone, nome);
      } else {
        printf("Comando %c desconhecido.\n", op);
      }
    }
    while (fgetc(stdin) != '\n')
      ;
  }

  liberar_base(&base);

  if (base.capacidade != 0) {
    printf("A base ainda tem capacidade %d.\n", base.capacidade);
  }
  if (base.armazenado != 0) {
    printf("A base ainda tem %d registros armazenados.\n", base.armazenado);
  }
  if (base.registros != NULL) {
    printf("A base ainda tem um pointeiro de registros.\n");
  }

  return 0;
}

Arquivo, de minha autoria, com as funções requeridas pela main acima:

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

typedef struct {
  int ra, telefone;
  char nome[100];
} Aluno;

typedef struct {
  int armazenado;
  int capacidade;
  Aluno *alunos;
} Base;

    
/* Funcao: criar_base
 *
 * Inicializa a base ja com a capacidade.
 *
 * Parametros:
 *   base: ponteiro para a base
 *   n: quantidade maxima de alunos
 */
void criar_base(Base *base, int n) {
 
    Aluno *al;

    al = (Aluno *) malloc(n * sizeof(Aluno));//Aloca espaço para n Alunos.

    (*base).capacidade = n; (*base).armazenado = 0, (*base).alunos = al;//Armazena os valores de inicialização.
    printf("Base criada.\n");//Imprime que a base foi criada.
}

/* Funcao: buscar
 *
 * Parametros:
 *   base: ponteiro para a base
 *   ra: numero do RA
 *
 * Retorno:
 *   Indice do registro com RA no vetor de alunos
 *   -1 caso contrario.
 */
int buscar(Base *base, int ra) {

  int tam = (*base).armazenado;//Guarda o tamanho numa variável.
  for(int i = 0; i<tam; i++)//Percorre o vetor alunos até seu final.
      if((*base).alunos[i].ra == ra)//Ao encontrar, retorna o índice i.
          return i;

  return -1;//Se não retornou i é porque não encontrou aluno. Retorna -1.
}

/* Funcao: imprimir
 *
 * Parametros:
 *   base: ponteiro para a base
 *   ra: numero do RA
 */
void imprimir(Base *base, int ra) {

   int pos = buscar(base, ra);//Encontra a posição de aluno.

   if(pos == -1){//Se -1, não foi encontrado aluno.
        printf("Aluno %d nao encontrado.\n", ra); 
       return;
   }
   //Caso contrário, imprime os dados do aluno. 
   printf("%d - %d - %s\n", (*base).alunos[pos].ra, (*base).alunos[pos].telefone, (*base).alunos[pos].nome);

}

/* Funcoes: adicionar
 *
 * Inclui um registro sem permitir RAs duplicados.
 * O quantidade de alunos deve ser atualizada.
 *
 * Parametros:
 *   base: ponteiro para a base
 *   ra: numero do RA
 *   telefone: numero do telefone
 *   nome: string com o nome
 */
void adicionar(Base *base, int ra, int telefone, char *nome) {

    int pos = buscar(base, ra), i, adicionado = 0;//Armazena o resultado da busca do aluno em pos.
    
    if(pos == -1){//Se -1, não foi encontrado aluno, logo ele deverá ser adicionado.
        
        if((*base).armazenado >= (*base).capacidade) {//Mas, se estiver cheia a base:
            printf("Erro: base cheia.\n"); 
            return;
        }
        //Caso contrário:
        pos = (*base).armazenado, adicionado = 1;
    }
          
    //Adiciona ou atualiza os dados ra e telefone na posição pos, que pode ser o índice retornado pela busca ou a última posição do vetor alunos.
    (*base).alunos[pos].ra = ra, (*base).alunos[pos].telefone = telefone;
    //Adiciona ou atualiza o nome do aluno.
    for(i = 0; nome[i] != '\0'; i++)
        (*base).alunos[pos].nome[i] = nome[i];
    (*base).alunos[pos].nome[i] = '\0';//Adicionar o '\0' ao nome do aluno.

    //Incrementa o armazenado, se adicionado, e imprime mensagem do resultado na tela.
    if(adicionado)
        (*base).armazenado += 1, printf("Adicionado: ");
    else 
        printf("Alterado: "); 

    printf("%d - %d - %s\n", (*base).alunos[pos].ra, (*base).alunos[pos].telefone, (*base).alunos[pos].nome);

}

/* Funcoes: remover
 *
 * Remove um registro se o ra estiver presente.
 * O quantidade de registro deve ser atualizada.
 *
 * Parametros:
 *   base: ponteiro para a base
 *   ra: numero do RA
 */
void remover(Base *base, int ra) {

    int pos = buscar(base, ra), i;//Armazena o resultado da busca do aluno em pos.

    if(pos == -1){//Se não encontrado aluno:
        printf("Aluno %d nao encontrado.\n", ra); 
    return;
    }
   
    //Caso encontrado, move o próximo aluno do vetor alunos para a posição do aluno anterior.
    for(i = pos; i < (*base).armazenado; i++)
        (*base).alunos[i] = (*base).alunos[i+1];
    
    //Armazena que há -1 aluno na base.
    (*base).armazenado -= 1; 
    
    //Imprime resultado da operação.
    printf("Aluno %d removido.\n", ra);

}

/* Funcao: liberar_base
 *
 * Libera a memoria de todos alunos da base.
 * Deve deixar a base com capacidade e quantidade armazenada igual a zero
 * e o ponteiro para alunos igual a NULL.
 *
 * Parametros:
 *   base: ponteiro para a base
 */
void liberar_base(Base *base) {
    //Libera o vetor alunos e atualiza capacidade e quantidade armazenada.
    free((*base).alunos);
    (*base).capacidade = 0, (*base).armazenado = 0, (*base).alunos = NULL;
}