As linguagens de programação normalmente oferecem facilidades para construir tipos compostos por agregados de outros elementos. Estruturas agregadas uniformes, onde todos os elementos são de um mesmo tipo arranjados em uma área contígua de memória, constituem arranjos ou vetores seqüenciais (Fig. 2.1b); seus elementos podem ser acessados através de um índice representando a posição desejada.
Em C, arranjos são definidos e acessados através do operador de
indexação []
, como em:
int elem[5]; // definição: arranjo com cinco inteiros ... elem[0] = 1; // acesso ao primeiro elemento do arranjo
Neste exemplo, um arranjo de nome elem é definido na função
main. Este arranjo tem espaço para armazenar cinco valores
inteiros, que serão referenciados no programa como elem[0],
elem[1], elem[2], elem[3] e elem[4].
Observe através desse exemplo que o primeiro elemento de um arranjo em C é
sempre o elemento de índice 0 (elem[0]
). Conseqüentemente, para um
arranjo com N elementos o último elemento é o de índice
N-1 (elem[4]
, no exemplo).
A implementação de arranjos está intimamente ligada ao conceito de
ponteiros. Quando se cria, como acima, um arranjo com cinco inteiros,
reserva-se o espaço na memória para armazená-los e atribui-se um nome
para o endereço inicial dessa área -- em outras palavras, um
ponteiro. O acesso ao valor i-ésimo elemento do arranjo
elem, elem[i]
, equivale à expressão
*(elem + i)Em C, as duas formas de indicar o elemento acessado podem ser usadas indistintamente.
Agregados não-uniformes, com componentes de tipos distintos, constituem registros (Fig. 2.1c). Em C, registros são definidos através do uso da construção struct, como em:
struct { int a; float b; } x; // definição da estrutura
A forma geral de definição de uma estrutura C é
struct tag { /* declaracao de componentes: */ ... } var1, var2, ..., varN;
A palavra chave struct inicia a definição da estrutura. A etiqueta (tag) é opcional, porém deve estar presente caso se deseje referenciar esta estrutura em algum momento posterior. Da mesma forma, a lista de variáveis declaradas (var1,..., varN) também não precisa estar presente -- a não ser que a etiqueta não esteja presente.
Quando a etiqueta está presente na definição de uma estrutura, variáveis com essa mesma estrutura podem ser definidas posteriormente. O exemplo acima poderia ter separado a definição da estrutura, como em:
struct simples { int a; float b; };da declaração da variável com esse tipo de estrutura, como em
struct simples x;
Muitas vezes, definições de estruturas estão associadas ao uso do comando typedef (definição de tipo), que associa um nome simbólico a algum tipo básico da linguagem C (ver Seção C.2.6). No exemplo, um nome de tipo Simples poderia estar associado à estrutura definida através da expressão:
typedef struct simples Simples;e então declarar x como
Simples x;
Uma vez que uma estrutura tem componentes internos que devem ser
acessados para processamento, algum mecanismo de acesso deve ser
fornecido pela linguagem. C oferece dois operadores que permitem
acessar elementos de estruturas. O operador básico de acesso a
elementos de estruturas é o operador .
(ponto). Por exemplo,
para atribuir o valor 1 ao componente a de x, a
expressão usada é
x.a = 1; // acesso
A outra forma de expressar acesso aos elementos de uma estrutura está
associada ao conceito de ponteiros para estruturas -- neste caso, o
operador ->
(seta) é utilizado. Considere o exemplo
Simples *y; // um ponteiro para uma estrutura y = &x; y->a = 1; // equivalente ao exemplo anterior
Observe que a expressão y->a
equivale à (*y).a
, sendo
simplesmente uma notação mais confortável para denotar a mesma
operação.