Capítulo 7 - Outros Tipos de Dados


Conteúdo  Capítulo anterior  Capítulo seguinte 

Neste capítulo discutimos como se podem criar em C tipos de dados mais avançados e estruturados.


Tópicos



Estruturas

As estruturas em C são muito semelhantes aos registos em Pascal. Agrupam num único tipo vários valores (campos), que podem ser de tipos diferentes. Exemplo:

struct people {
  char name[50];
  int age;
  float salary;
};

struct people funcionarios;

As declarações anteriores definem uma estrutura chamada people e uma variável (funcionarios) desse tipo. Note-se que a estrutura definida tem um nome (tag) que é opcional. Quando as estruturas são definas com tag podemos declarar posteriormente variáveis, argumentos de funções, e também tipos de retorno, usando esse tag, como se mostrou no exemplo anterior. É também possível definir estruturas sem tag (anónimas). Neste último caso as variáveis terão de ser nomeadas entre o último } e ; da forma habitual. Por exemplo:

struct {
  char name[50];
  int age;
  float salary;
} funcionarios;

Podemos ainda inicializar as variáveis do tipo estrutura quando da sua declaração, colocando os valores pela ordem dos campos definidos na estrutura entre chaves:

struct people funcionarios = { "John Smith", 26, 124.5 };

Para acessar  um campo, ou membro, de uma estrutura utiliza-se, à semelhança do Pascal, o operador . . Para aumentar o salário do Sr. John Smith deveria escrever-se:

funcionarios.salary = 150.0;

 

Up

Uso de typedef

A definição de novos tipos com typedef pode também ser efetuada com estruturas. A declaração seguinte define um novo tipo person, podendo posteriormente declarar-se e inicializar-se variáveis desse tipo:

typedef struct people {
  char name[50];
  int age;
  float salary;
} person;

person John = { "John Smith", 26, 124.5 };

Neste exemplo o nome people também funciona como tag da estrutura e também é opcional. Nesta situação a sua utilidade é reduzida.

Arrays e estruturas podem ser misturados (aliás como quaisquer outros tipos):

typedef struct people {
  char name[50];
  int age;
  float salary;
} person;

person team[1000];

Aqui a variável team é composta por 1000 person's.

Um acesso poderia ser, por exemplo:

team[41].salary = 150.0;

ou,

total_salaries += team[501].salary;

 

Up

Uniões

Uma variável do tipo união pode conter (em instantes diferentes) valores de diferentes tipos e tamanhos. Na linguagem C a declaração de uniões é em tudo semelhante à declaração de estruturas, empregando-se a palavra union em vez de struct. Por exemplo, podemos ter:

union number {
  short sort_number;
  long long_number;
  double real_number;
} a_number;

Aqui declara-se uma união chamada number e uma variável desse tipo - a_number. Esta variável poderá conter, em instantes diferentes, um short, um long ou um double. A distinção faz-se pelo nome do campo respectivo. Quando se preenche um determinado campo, o que estiver noutro qualquer é destruído. Os vários campos têm todos o mesmo endereço na memória.

Os campos ou membros são acessados da mesma forma do que nas estruturas:

printf("%ld\n", a_number.long_number);

Quando o compilador reserva memória para armazenar uma união apenas reserva o espaço suficiente para o membro maior (no exemplo de cima serão 8 bytes para o double). Os outros membros ficam sobrepostos, com o mesmo endereço inicial.

Uma forma comum de num programa se tomar nota do membro ativo em cada instante é embeber a união dentro de uma estrutura, onde se acrescenta um outro membro com essa função. Examinar atentamente o exemplo que se segue:

typedef struct {
  int max_passengers;
} jet;

typedef struct {
  int lift_capacity;
} helicopter;

typedef struct {
  int max_payload;
} cargo_plane;

typedef union {
  jet jet_unit;
  helicopter heli_unit;
  cargo_plane cargo_unit;
} aircraft;

typedef struct {
  aircraft_type kind;
  int speed;
  aircraft description;
} an_aircraft;

No tipo an_aircraft inclui-se um membro description que é do tipo aircraft que é, por sua vez uma união de 3 estruturas diferentes (jet, helicopter e cargo_plane). Inclui-se ainda no tipo an_aircraft um membro (kind) que indica qual é o membro válido no momento para a união description.
 

Up

Conversão entre tipos (type casting)

O C é uma das poucas linguagens que permite a mudança de tipo das suas variáveis. Para isso usa-se o operador (cast), onde cast é o novo tipo pretendido. Assim é possível escrever:

int k;
float r = 9.87;

k = (int) r;

A variável k ficará com o valor 9, sendo a parte fraccionária de r descartada.

O casting pode ser usado com qualquer um dos tipos simples, e muitas vezes quando é omitido o compilador executa a conversão por default. Outro exemplo:

int k;
char ch = 'A';

k = (int) ch;

Aqui o valor de k será 65 (o código ascii do carácter 'A').

Outro uso frequente do casting é assegurar que a divisão entre inteiros não seja uma divisão inteira. Basta para isso converter para real o numerador ou denominador. O outro operando é assim também automaticamente convertido, antes de se efetuar a operação:

int j = 2, k = 5;
float r;

r = (float) j / k;     /* r = 0.4 em vez de 0, se não se fizesse o cast de j */

 

Up

Tipos enumerados

Os tipos enumerados não são mais do que uma lista de identificadores que funcionam como constantes inteiras. São muito semelhantes aos tipos enumerados do Pascal. Por exemplo:

enum days { sun, mon, tue, wed, thu, fri, sat };
enum days week1, week2;

week1 = wed;
week2 = sun;

Na declaração de cima o identificador sun fica associado ao valor 0, o identificador mon ao valor 1, e assim sucessivamente. É possível fazer cast (implícito ou explícito) para int, nos dois sentidos.

No entando é possível, numa enumeração, associar os identicadores a outros valores, que não a sucessão que começa em 0. Por exemplo:

enum escapes {bell='\a', backspace='\b', tab='\t', newline='\n', vertical_tab='\v', return='\r'};

É mesmo possível iniciar a sucessão de valores inteiros associados aos identificadores num valor diferente de 0, como na declaração seguinte:

enum months {jan=1, feb, mar, apr, may, jun, jul, ago, sep, oct, nov, dec};

No exemplo apresentado para as uniões, atrás, aparecia um tipo aircraft_type. Esse tipo pode ser definido como uma enumeração:

typedef enum {a_jet, a_helicopter, a_cargo_plane} aircraft_type;

 

Up

Variáveis estáticas

É possível, quando da declaração de variáveis, locais ou não, prefixá-las com o qualificador static. As variáveis locais estáticas são inicializadas uma só vez e não desaparecem quando a função a que pertencem termina, podendo no entanto ser acessadas apenas dentro da função. As variáveis globais estáticas apenas podem ser acessadas no arquivo onde são declaradas, não sendo exportadas para o exterior.

As variáveis locais estáticas também mantêm o seu valor de umas chamadas para as outras, como se vê no exemplo seguinte:

#include <stdio.h>

void stat(void);      /* Protótipo de stat() */

void main(void)
{
  int k;

  for (k=0; k<5; k++)
    stat();
}

void stat(void)
{
  int var = 0;
  satic int auto_var = 0;

  printf("var = %d, auto_var = %d\n", var++, auto_var++);
}

A saída deste programa será:

var = 0, auto_var = 0
var = 0, auto_var = 1
var = 0, auto_var = 2
var = 0, auto_var = 3
var = 0, auto_var = 4

A variável var é criada e inicializada de cada vez que a função é chamada. A variável auto_var só é inicializada da primeira vez e lembra-se do valor que tinha na última vez que a função terminou.
 

Up

Exercícios

Veja aqui os exercícios 

Up

[REV 03/1999]