Tutoriais e Programação

Linguagem C - Estruturas e Uniões

Sex

28

Nov

2008


12:09

  • Imprimir
(10 votos, média 4.90 de 5) 


C

Estruturas são peças contíguas de armazenamento que contém vários tipos simples agrupados numa entidade. Pode-se fazer uma analogia com uma estante de livros: se tivermos uma estante para 50 livros, o espaço para cada um dos 50 livros está garantido, esteja ou não na estante. Se fixarmos (melhor ainda, se identificarmos com uma etiqueta) onde cada um dos livros deve ser armazenado, sempre saberemos onde encontrar e onde guardar cada um dos livros. A estante funciona como estrutura, os locais como campos e os livros como dados.

Criando uma estrutura

Estruturas são manifestadas através da palavra-chave struct seguida pelo nome da estrutura e por uma área delimitada por chaves que contém os campos. Os campos também são manifestados da forma habitual, . Veja abaixo:

struct coordenadas { int x; int y; }

Lembre-se de que o manifesto de uma variável do tipo estrutura é apenas um aviso para o pre-processador (se tiver dúvidas, reveja Bibliotecas e Tipos) - a entidade existe, mas não possui dados. Usando esta nova entidade, que na verdade é um novo tipo criado por nós, podemos manifestar ou definir variáveis ou objetos deste novo tipo:

struct coordenadas coordTela {35,98};

Aqui definimos a variável coordTela, que é uma estrutura do tipo coordenadas, que possui dois campos de inteiros, o "x" e o "y". Aproveitamos o embalo e indicamos os valores 35 e 98 (observe que os valores estão entre chaves). O pre-processador, quando processar esta definição, atribuirá o valor 35 para o campo x e o valor 98 para o campo y.

Acessando dados

Existem duas formas de acessar dados armazenados numa estrutura. Para obter diretamente o valor de um campo, a forma é . . Para obter o valor de um campo apontado por um ponteiro, a forma é -> .Veja o exemplo abaixo:

void fn(void) { coordenadas c; coordenadas *pc; coordenadas &rc = c; c.x = 35; // Atribui o valor 35 para o campo x c.y = 98; // Atribui o valor 98 para o campo y pc = &c; // Faz pc apontar para c pc->x = 67; // Muda o valor do campo x para 67 pc->y = 33; // Muda o valor do campo y para 33 rc.x = 88; // Referências usam a notação de ponto }

Recursividade

Estruturas podem ser recursivas, isto é, podem conter ponteiros para si mesmas - o que é o mesmo que dizer que podem "se chamar". Esta peculiaridade ajuda a definir estruturas do tipo lista:

struct lista { struct lista *Next; int Dado; }

Aqui definimos uma estrutura que contém um ponteiro para a mesma estrutura no primeiro campo e um inteiro no segundo campo. Mas ATENÇÃO: estamos fazendo o manifesto de um ponteiro para uma outra estrutura idêntica, NÃO a própria. Uma estrutura não pode conter ela mesma!

Listas duplas podem ser manifestadas da forma mostrada abaixo, com dois ponteiros: um para o próximo elemento da lista (*Next) e um para o elemento anterior (*Previous).

struct lista_dupla { struct lista_dupla *Next; struct lista_dupla *Previous; int Dado; };

Campo de bits

Um manifesto especial que só pode ser usado em estruturas é o campo de bits. Com ele pode-se especificar um campo da estrutura com um certo número de bits. Veja o exemplo:

struct flags { unsigned JaFoiProcessado:1; unsigned JaFoiImpresso:1; unsigned Paginas:5; };

Esta estrutura possui três campos. Os dois primeiros são campos de 1 bit, isto é, só podem conter um valor lógico (ou booleano) de 0 ou 1. O terceiro campo pode armazenar um inteiro de 5 bits, ou seja, números de 0 a 31.

Estruturas aninhadas

Estruturas podem conter outras estruturas ou tipos. Por exemplo, tendo manifestado a estrutura coordenadas (veja acima), é possível manifestar uma nova estrutura que a contenha:

struct Ponto { struct coordenadas coordTela; int Dado; };

Esta estrutura contém uma estrutura "coordenadas". Para acessar o campo "x" da estrutura coordTela contida na estrutura Ponto, basta referenciá-lo com:

struct Ponto pto; ... pto.coordTela.x = 78;

Estruturas em arrays

Arrays (ou matrizes) podem conter estruturas. Abaixo está o manifesto de um array com 25 estruturas do tipo coordenadas:

struct coordenadas arrayCoord[24];

Lembre-se que os elementos dos arrays são numerados a partir de 0 (zero). Neste caso, os elementos são numerados de 0 a 24, perfazendo 25 elementos. Se quisermos acessar o "x" do sexto elemento, escrevemos:

arrayCoord[5].x = 48;

Um bom exemplo de uso

O número de estruturas possíveis é praticamente infinito. As estruturas podem ser modeladas de acordo com a necessidade e o projeto. De qualquer forma, são extremamente versáteis e permitem atribuir, obter e modificar dados com facilidade. Veja um exemplo prático, como se fosse um registro de uma tabela de dados:

struct mailsRecebidos { int IDmail; time_t data_hora; char *Remetente; char *Assunto; char *Texto; char *Anexos; };

Esta estrutura, de nome mailsRecebidos, é composta pelos seguintes campos: um número inteiro para armazenar a identificação do email (IDmail), um time_t (tipo time) para armazendar a data e a hora (data_hora) e mais quatro campos com endereços apontando para o início de uma string de caracteres.

Uniões

union inteiroFlutuante { int i; double d; };

Sabemos que um número inteiro (int), no lcc-win32, possui o tamanho 4 e que o um número de precisão dupla (double) ocupa 8 bits. Para poder acomodar qualquer um dos dois valores declarados, é claro que esta união vai reservar 8 bits. Num dado momento, apenas um dos números poderá ser armazenado, nunca os dois juntos. E qual é a vantagem que Maria leva?

Bem, uma união funciona mais ou menos como um rascunho ocupando um número fixo de bits na memória. Imagine o seguinte: num determinado programa manifestamos um montão de estruturas ligeiramente diferentes que nunca serão usadas simultaneamente. No momento em que forem definidas e receberem valores, cada uma delas ocupará determinado espaço na memória. Quando tivermos usado cada uma delas, uma grande área da memória estará alocada, mas apenas uma pequena porção, referente à estrutura em uso no momento, estará sendo utilizada.

É aí que está o pulo do gato: empacotamos as estruturas numa união. A união reserva um espaço correspondente à maior estrutura da lista e o resultado é que trocamos a soma dos espaços necessários para cada estrutura pelo espaço necessário para a maior delas. Cada vez que quisermos trabalhar com uma das estruturas, podemos copiar a mesma para a união porque temos a certeza de que haverá espaço suficiente para contê-la.

Resumindo: uniões são uma forma prática e elegante de economizar memória!

Observações da vó

Estruturas são excelentes para manter a ordem e tornarem o código fonte legível. Práticas, rápidas e eficientes, não é à toa que são utilizadas com frequência em aplicativos e sistemas operacionais que dependam de desempenho e de confiabilidade.

Por outro lado, as uniões são as "muquiranas" que garantem um melhor aproveitamento da memória. Formam uma dupla dinâmica com qualquer tipo de variável, inclusive com estruturas, controlando o apetite voraz de aplicativos extensos ou de sistemas operacionais.

Mas, apesar de tantos elogios, o Ministério da Saúde adverte: use com moderação wink

компромат Вадим Логофет сковорода блинная биол чугунная отзывыкомпания ооо полигонсмартфондепутат лобановскийсобытия харьков май 2016сайт никас