Universidade Federal de Minas Gerais
Instituto de Ciências Exatas
Departamento de Ciência da Computação

Algoritmos e Estruturas de Dados I

Estruturas


As linguagens de programação procuram dar suporte à implementaçao do conceito de Agregação ou Composição de dados. Na linguagem C a base deste suporte são as estruturas (as estruturas são chamadas de “registro” em algumas linguagens) . Uma estrutura é constituída de uma seqüência de elementos chamados de “componentes” ou “campos”. Cada componente pode ser de qualquer tipo. Fazendo uma analogia entre arranjos e estruturas: nos arranjos temos seqüência de componentes, todos do mesmo tipo, nas estruturas temos seqüências de componentes cada um deles de um tipo arbitrário. Nos arranjos usamos o operador de indexação, para acessar um componente nas estruturas usamos um operador de seleção para acessar um componente.

Abaixo vemos a definição de uma estrutura que modela os dados de uma pessoa:

struct Pessoa{
  char nome[80];
  int diaNasc;
  int mesNasc;
  int anoNasc;
} fulano, beltrano;

O trecho acima primeiramente define uma estrutura com uma “etiqueta” (“tag”) Pessoa, além disso são definidas duas variáveis: fulano e beltrano. A definição de variáveis pode ocorrer no momento da definição da estrutura, como o caso das variáveis fulano e beltrano acima e também após a definição de uma estrutura que tenha uma etiqueta podemos usar uma “abreviatura” para definir outras variáveis, por exemplo:

struct Pessoa ciclano;

Agora passamos a ter três variáveis (fulano, beltrano e ciclano). struct Pessoa corresponde a uma definição de tipo, um esqueleto, um modelo, um gabarito e não ocupa área de memória da maneira que fulano, beltrano e ciclano ocupam, mas podemos aplicar o operador “sizeof” tanto ao tipo quanto à variável, ou seja podemos usar ambos comandos:
printf("%d\n", sizeof( struct Pessoa));
printf("%d\n", sizeof(fulano));

Em ambos os casos acima sizeof retorna a quantidade de bytes que o tipo define ou o número de bytes da variável.

O acesso aos componentes (campos) da estrutura são feitos através do operador seleção (. (ponto)), veja os exemplos a seguir:

fulano.diaNasc=27;
beltrano.mesNasc=7;
strcpy(ciclano.nome, “Jose Silva”);

O conceito de etiqueta é um conceito novo. Temos um tipo “geral” que é o tipo “struct” mas um tipo “struct” tem mais detalhes tais como quantos campos, o nome dos campos, o tipo dos campos etc. A variável fulano de uma maneira “geral” é do tipo “struct”, mas em particular é do tipo struct com etiqueta Pessoa. A etiqueta é opcional. Podemos definir uma estrutura sem etiqueta:
struct {
  char nome[80];
  int diaNasc;
  int mesNasc;
  int anoNasc;
} fulano, beltrano, ciclano;

Mas no caso acima não temos mais a abreviatura struct Pessoa para a definição. Mas podemos utilizar typedef para definir o tipo Pessoa. Conforme explicado no material de “typedef”, quando precedemos uma definição com a palavra “typedef”: o identificador que normalmente corresponderia a um nome de variável passa a ser um nome de tipo:

typedef struct {
  char nome[80];
  int diaNasc;
  int mesNasc;
  int anoNasc;
} Pessoa;

Pessoa fulano, beltrano, ciclano;

Podemos aplicar o operador “sizeof” ao nome do tipo definido no typedef.

 

Podemos definir variáveis do tipo estrutura com ou sem inicialização.

struct X{int a; double b;} x = {10, 20.};

struct X y={20, 30.};

Não podemos inicializar os componentes individualmente diretamente:
struct {int a=2;}v; //erro

Podemos ter ponteiros para estruturas:

struct Pessoa *pe;

e podemos atribuir o endereço de uma instância para um ponteiro:

pe=&fulano;

O acesso aos campos de uma instância de estrutura podem ser feitos da seguinte maneira(Opção I):

(*pe).mesNasc=8;

ou usando o operador menos seguido de maior (operador seta!) -> (Opção II)

pe->mesNasc=8;

As únicas operações “legais” sobre as instâncias de estruturas é copiar ou atribuir como uma unidade (p.ex. ciclano=beltrano;), obter o endereço (p.ex. &fulano), e selecionar os membros (p.ex. printf(“%d”, fulano.disNasc);).

É interessante observar que não podemos copiar um arranjo sobre um outro arranjo:

int a1[]={10,20,30}; int a2[3];
a2=a1; //erro

mas podemos copiar uma (instância de) estrutura sobre outra:

struct X{int a[3];} e1={{10,20,30}};
struct X e2;
e2=e1;

Não podemos considerar o tipo struct como um “cidadão de primeira classe” pois ainda há um certo desejo que ele tivesse certos privilégios permitidos ao tipo int mas não permitidos ao tipo struct (por exemplo o programador não pode comparar nem pela igualdade duas variáveis do tipo struct!)

Pessoa fulano, beltrano, ciclano;
inicia(fulano);
beltrano=fulano; //ok
if(
beltrano==fulano) //ERRO

 

Estruturas podem ser aninhadas em termos de composição ou mesmo definição (em alguns compiladores):

struct Y{int ii;};
struct X{struct Y campo1; int jj;} var;
O trecho acima é similar a:
struct X{struct Y{int ii;} campo1; int campo2;} var;
Apesar do aninhamento struct Y tem o mesmo “escopo”de struct X e podemos ter:
struct X{struct Y{int ii;} campo1; int campo2;} var;
struct Y var2;
em alguns compiladores (e,g, GCC);

Não existe escopos aninhados de estruturas na linguagem C. O usual na linguagem é evitar o aninhamento de definições:

struct CEP{int parte5dig; int parte3dig;};
struct ENDERECO{char logradouro[100]; struct CEP cep;} enderecoUFMG;
strcpy(enderecoUFMG.logradouro, “Av.
Antonio Carlos 6627”);
enderecoUFMG.cep.parte5dig=31270; enderecoUFMG.cep.parte3dig=10;