struct people {
char name[50];
int age;
float salary;
};
struct people John;As declarações anteriores definem uma estrutura chamada people e uma variável (John) 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 {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 chavetas:
char name[50];
int age;
float salary;
} John;
struct people John = { "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:
John.salary = 150.0;
typedef struct people {Neste exemplo o nome people também funciona como tag da estrutura e também é opcional. Nesta situação a sua utilidade é reduzida.
char name[50];
int age;
float salary;
} person;person John = { "John Smith", 26, 124.5 };
Arrays e estruturas podem ser misturados (aliás como quaisquer outros tipos):
typedef struct people {Aqui a variável team é composta por 1000 person's.
char name[50];
int age;
float salary;
} person;person team[1000];
Um acesso poderia ser, por exemplo:
team[41].salary = 150.0;ou,
total_salaries += team[501].salary;
union 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.
short sort_number;
long long_number;
double real_number;
} a_number;
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 {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.
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;
int k;A variável k ficará com o valor 9, sendo a parte fraccionária de r descartada.
float r = 9.87;k = (int) r;
O casting pode ser usado com qualquer um dos tipos simples, e muitas vezes quando é omitido o compilador executa a conversão silenciosamente. Outro exemplo:
int k;Aqui o valor de k será 65 (o código ascii do carácter 'A').
char ch = 'A';k = (int) ch;
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 */
enum days { sun, mon, tue, wed, thu, fri, sat };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.
enum days week1, week2;week1 = wed;
week2 = sun;
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;
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>A saída deste programa será: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 st_var = 0;printf("var = %d, auto_var = %d\n", var++, auto_var++);
}
var = 0, auto_var = 0A 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.
var = 0, auto_var = 1
var = 0, auto_var = 2
var = 0, auto_var = 3
var = 0, auto_var = 4
2. Escreva um programa que construa uma base de dados simples relativa
a pessoas. Deverá armazenar o nome, morada, data de nascimento,
salário e categoria.