ESTRUTURA DE DADOS COMPOSTA HETEROGÊNEA

 

Um uso bastante frequente na Linguagem C é a elaboração de estruturas de dados heterogêneas, mas vulgarmente conhecidas em outras linguagens de programação como registros. Para um melhor entendimento inicial da funcionalidade de uma estrutura observe a figura abaixo.

 

 

 

Essa ficha de inscrição apenas coleta alguns dados de um indivíduo qualquer e serve de exemplo do que vem a ser um registro ou estrutura de dados heterogênea.

 

Uma estrutura nada mais é do que uma coleção de algumas variáveis, possivelmente de tipos diferentes, que agrupam certas informações logicamente relacionadas em um único nome, ou seja, o identificador da estrutura de dados heterogêneos. Essas variáveis são os membros da estrutura e são conhecidas como elementos ou componentes da mesma. Acompanhe o exemplo descrito na linguagem de programação C para melhor compreender esta estrutura.

 

struct conta_bancaria
{
  char cliente[30];   // componente para o nome do cliente
  int agencia;        // componente para indicar a agência do cliente
  int conta;          // número da conta do cliente
  float valor;        // componente que identifica o valor do lançamento
  char tipo;          // tipo de operação bancaria, sendo D=débito e C=crédito
};

 

Observe no exemplo acima que os membros são relacionados, pois o nome do cliente está ligado às suas operações bancárias em sua conta e agência.

 

As estruturas heterogêneas constituem um recurso importante para a organização dos dados utilizados devido à possibilidade de tratar um grupo de valores como uma única variável, similar às estruturas homogêneas (vetor e matriz). Observe também que a declaração de conta_bancaria define uma estrutura que pode tornar-se um tipo de dado a ser utilizado em declarações de variáveis. É importante atentar que a declaração da estrutura acima não cria nenhuma variável de acesso a esta estrutura, ela apenas cria a estrutura de dado usando a palavra reservada struct.

 

Esta palavra informa ao compilador que um modelo de estrutura está sendo definido na memória do computador. Depois desta criação será possível declarar variáveis que a utilizem como um tipo da estrutura onde variáveis poderão armazenar valores respeitando suas características.

 

Forma Geral de Definição da struct

 

struct <identificador>
{
     <tipo dado>  <identificador>;
};
 
 
  • <identificador> define o nome da struct e de seus membros ou componentes
  • <tipo dado> define o tipo de dado de cada componente da struct
 

A declaração da variável que armazenará dados neste tipo de estrutura definida pela palavra reservada pode ser feita juntamente com a especificação da struct ou separadamente em qualquer lugar onde o escopo desta struct seja válido.

 

struct <identificador>
{
   <tipo dado> ;
} <variável>;

 

ou após o ponto e vírgula da declaração da struct a inserção da instrução:

 

struct <identificador da struct já definida anteriormente> <variável>;

 

<variável> consiste na variável que acessará os membros da struct

 

Exemplos:

 

struct conta_bancaria
{
   char cliente[30];
   int agencia;    
   int conta;         
   float valor;       
   char tipo;        
}  lancamento; // lancamento consiste na variável da struct conta_bancaria
 

 

Para a segunda possibilidade de criação da variável de acesso a struct conta_bancaria a declaração consistiria somente na linha abaixo, porém antes já deveria ter sido especificada a struct sem nenhuma variável de acesso.

 

struct conta_bancaria lancamento; // só declara a variável lacamento

 

A declaração de uma struct pode ser feita com a especificação do nome da struct e da variável de acesso a mesma, ou somente com o nome da struct, ou somente com o nome da variável de acesso a struct, mas nunca com a ausência dos dois nomes.

 

Somente será alocado espaço na memória do computador, para armazenamento dos dados de uma struct, após a declaração de uma variável de acesso a essa struct. A quantidade de componentes em uma struct corresponde a quantidade de memória disponível no computador onde o programa será executado, sendo, normalmente, uma quantidade enorme, porém finita.

 

Os elementos que estão presentes em uma struct são referenciados através do operador ponto (.), respeitando a seguinte forma geral:

 
  • <nome da struct> . <nome do componente>
  • <nome da struct> nome da struct anteriormente definifa (declarada)
  • <nome do componente> nome do componente a ser acessado na struct
 

Observe o exemplo de manipulação de uma struct:

 

/* 
    SÍNTESE
           Objetivo: cadastra os dados de um lançamento bancário
           Entrada: nome do cliente, agência, conta, valor e operação
           Saída: dados cadastrados para o lançamento desejado
*/
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
struct banco
{
   char cliente[30];
   int agencia;
   int conta;
   float valor;
   char tipo;  // D para débito e C para crédito
};
 
int main(void)
{
   struct banco lancamento;     // declaração da variável lancamento
   printf("Informe o nome do cliente: ");
   gets(lancamento.cliente);   // lê nome do cliente em lancamento
   fflush(stdin);         // limpa o buffer entre uso de gets com scanf
   printf("Informe o número de sua agência: ");
   scanf("%d", &lancamento.agencia);  // lê a agência de lancamento
   printf("Digite o número de sua conta: ");
   scanf("%d", &lancamento.conta);
   printf("Informe o valor da operação: R$ ");
   scanf("%f", &lancamento.valor);
   printf("Digite D para operação de débito ou C para crédito. ");
   do{           // aceita somente os 2 valores válidos
      lancamento.tipo = toupper(getche());   // lê sempre maiúsculo
   } while (lancamento.tipo != 'D' && lancamento.tipo != 'C');
   clrscr();                // limpa a janela de tamanho padrão

// Apresentação dos dados lidos
   printf("Dados Armazenados\n);
   printf("\tCliente..........:%s\n", lancamento.cliente);
   printf("\tAgencia........:%d\n", lancamento.agencia);
   printf("\tConta............:%d\n", lancamento.conta);
   printf("Saldo.............:%4.2f\n", lancamento.saldo);
   printf("Tipo..............:");
   lancamento.tipo == 'D' ? puts("Débito") : puts("Crédito");
   getch();     // aguardar visualização dos resultados pelo usuário
   return 0;

}    // fim programa 

 

A utilização de matrizes de estruturas é um recurso muito comum no registro de informações, pois a junção destes dois tipos de estrutura de dados (heterogênea e homogênea) permite ao computador armazenar e manipular, mais eficientemente, um conjunto de dados.

 

Para combinação destas estruturas de dados, torna-se, primeiramente necessária, a definição da struct (estrutura heterogênea) e posteriormente a declaração de uma variável que seja uma matriz (estrutura homogênea) dessa struct que corresponderá ao tipo de dados da matriz. Veja o exemplo a seguir:

 

/*
   SÍNTESE
       Objetivo:   registra os candidatos no vestibular
       Entrada:   nome, curso, ano atual e avaliação alcançada
       Saída:      confirma o registro do candidato
*/

#include <stdio.h>
#include <conio.h>
struct inscricao     // declara estrutura heterogênea
{
   char nome[30];
   char curso[20];
   int ano;
   float nota;
};
int main(void)
{
   int contador;
   struct inscricao vestibular[50];     // matriz de 50 inscricao 
   for(contador = 0; contador < 50; contador++)
   {
      printf("Informe o nome do candidato: ");
      gets(vestibular[contador].nome);
      printf("Informe o curso desejado: ");
      gets(vestibular[contador].curso);
      fflush(stdin);
      printf("Digite o ano atual (exemplo 2003: ");
      scanf("%d", &vestibular[contador].ano);
      printf("Avaliação obtida: ");
      scanf("%f",&vestibular[contador].nota);
      fflush(stdin);    // limpa buffer de memória para repetição
      printf("\n\n\nCandidato %2d registrado.\n\n", contador);
   }
   getch();     // aguardar visualização dos resultados pelo usuário
   return 0;

}    // fim programa

 

Na manipulação de struct ainda é possível copiar todos os dados de uma variável de struct para outra variável desta mesma struct. Para isso é feita uma atribuição normal entre as variáveis, porém isso só é possível para variáveis que sejam de um mesmo tipo de struct. Observe o exemplo abaixo supondo a declaração das variáveis vestibular e estudante.

 
 
struct inscricao
{
   char nome[30];
   char curso[20];
   int ano;
   float nota;
} vestibular, estudante;
 
 

Note que esta declaração não corresponde a uma matriz de struct, mas declara duas variáveis diferentes com a mesma struct como seus tipos. Após a leitura de todos os componentes desta struct será possível copiá-los, todos com a simples atribuição abaixo, onde todos os dados de vestibular serão idênticos aos dados de estudantes.

 
  • // após a leitura de todos os dados de vestibular...
  • vestibular = estudante; // atribuição entre variáveis da mesma struct
 

A Linguagem C permite também a criação de ponteiros para struct, onde a declaração do ponteiro obedece o mesmo padrão de definição de ponteiros, ou seja, a inserção do operador de derreferenciamento (usando o *) a frente do nome da variável que acessará a struct.

 

struct inscricao *p_vestibular; // cria ponteiro p_vestibular para inscricao

 

O uso de ponteiro para struct funciona como um ponteiro convencional, pois acessa o endereço de memória onde a struct está armazenada. Mais precisamente, um ponteiro para struct, aponta para o primeiro endereço de armazenamento dos dados que compõem esta struct referenciada.

 

No entanto, a manipulação dos componentes de uma struct acessada por meio de ponteiros deverá acontecer através do operador seta (->), ao invés do operador ponto (.). Veja o exemplo mais elucidativo a seguir:

 

/*
   SÍNTESE
       Objetivo: cadastra os dados da inscricao de um aluno
       Entrada: nome do aluno, curso, identificador, nota e condiçao
       Saída: dados cadastrados e situaçao do aluno
*/

#include <stdio.h>
#include <conio.h>
#include <ctype.h>
 struct inscricao
    {
      char nome[30];
      char curso[30];
      int Id;          // numero que indentifica o aluno 
      float nota;
      char condicao;   // A para aprovado e R para reprovado
    } estudante;       // declaração da variável estudantes
void alteraStruct (struct inscricao *p_estudante);   // declara procedimento

int main(void){
   // Declarações
		
   // Instruções
   
   printf("Informe o nome do estudante: ");
   gets(estudante.nome);
   fflush(stdin);
   printf("Digite o nome do curso: ");
   gets(estudante.curso);
   printf("Informe a nota do aluno nesta disciplina: ");
   scanf("%f",&estudante.nota );
   printf("Informe o número do Id: ");
   scanf("%d", &estudante.Id);
   alteraStruct(&estudante);       // aciona o procedimento
   system("cls");
   
   // Apresentação dos dados lidos 
   
   printf("Dados Armazenados\n");
   printf("\tNome..........:%s\n", estudante.nome);
   printf("\tCurso........:%s\n", estudante.curso);
   printf("\tId.............:%d\n", estudante.Id);
   printf("\tNota.............:%f.1\n", estudante.nota);
   printf("\tCondicao..............:");
   estudante.condicao == 'A' ? puts("aprovado") : puts("reprovado");
   getch();
   return 0;

}

// Corpo do procedimento

void alteraStruct (struct inscricao *p_estudante)
{
  if ((*p_estudante).nota >= 5){         // acessa conteúdo do dado e verifica
    p_estudante->condicao = 'A';       	 // acessa endereço do dado
  }else{
      p_estudante->condicao = 'R';
  }
}

 

Observando este exemplo com cuidado é possível verificar o acesso ao endereço de memória que possui os dados armazenados na struct. Porém este acesso é feito de forma diferente, de acordo com operador usado em sua manipulação.

 

A manipulação (*p_estudante).nota acessa o endereço da struct e o conteúdo do seu componente, enquanto que a p_estudante->condicao chega ao endereço do componente para depois manipulá-lo. Sendo assim, o valor da nota foi lido pelo procedimento, enquanto que o valor da condicao foi inicializado, pois ainda não possuíam conteúdo algum.

 

Atividade de Fixação

 

No intuito de fixar os novos conteúdos abordados por este módulo e verificar sua compreensão sobre os mesmos, são sugerido alguns exercícios de fixação para serem resolvidos. Clique no link de exercícios ao lado para iniciar a lista de exercícios referente a este conteúdo abordado. Bons estudos sobre os mesmos!!