SlideShare uma empresa Scribd logo
1 de 39
Baixar para ler offline
Disciplina: Programação de Sistemas
Informáticos
Ano Letivo 2011/2012
Aida Meira
Curso Profissional de Técnico de Gestão e
Programação de Sistemas Informáticos
Módulo V
Estrutura de Dados Composta
Estruturas
de
Dados
Compostas
 

M"
2 Professora Aida Meira
INDICE


1.
 Apontadores..................................................................................................3

A memória ........................................................................................................3

Apontadores .....................................................................................................5

Declaração .....................................................................................................10

Operadores ....................................................................................................11

Expressões.....................................................................................................12

Comparação...................................................................................................13

Ponteiros e vetores ........................................................................................13

Ponteiros como parametros de funções.........................................................16

Ponteiros para funções ..................................................................................20

2.
 Tipos Estruturados......................................................................................23

O tipo estrutura...............................................................................................23

Ponteiro para estruturas.................................................................................25

Passagem de estruturas para funções...........................................................26

Definição de “novos” tipos..............................................................................28

Vetores de estruturas .....................................................................................30

Vetores de ponteiros para estruturas.............................................................32

Estruturas
de
Dados
Compostas
 

M"
3 Professora Aida Meira
1. Apontadores

A
MEMÓRIA

A memória de um computador encontra-se organizada em células ou palavras
de memória individuais. Cada palavra de memória é referenciada por um
endereço e armazena um dado conteúdo. Designa-se por “número de bits da
arquitetura” o número máximo de bits que um processador ´e capaz de ler num
único acesso à memória. Cada palavra de memória de referência de um
processador tem em geral um número de bits idêntico ao número de bits da
arquitetura.








DOUBLE
FLOAT
i=
2450
k=113
j=11331
F=225.345 22.5E+14
5
INT
Estruturas
de
Dados
Compostas
 

M"
4 Professora Aida Meira
Admite-se aqui que a palavra de memória e o tipo inteiro são representados por
32 bits.
De acordo com a figura, durante a compilação foram atribuídos as variáveis i, j,
k, f os endereços 1002,1005, 1006 e 1004, respetivamente, enquanto a
variável d foi atribuído o endereço 1007.
Note-se que, com exceção do tipo double, cada variável tem uma
representação interna de 32 bits, ocupando por isso apenas um endereço de
memória. A variável d, de tipo double, tem uma representação interna de 64
bits, exigindo por isso duas palavras de memória: os endereços 1007 e 1008.
Na figura encontram-se representados outras posições de memória,
provavelmente ocupadas por outras variáveis, e cujo conteúdo é desconhecido
do programador.
Estruturas
de
Dados
Compostas
 

M"
5 Professora Aida Meira
APONTADORES

Um ponteiro é uma variável que contém um endereço
de memória, normalmente referenciando a posição de
uma outra variável.
(Schildt-1996)
Um apontador é uma variável cujo conteúdo é um endereço de outra posição
de memória. A declaração de variáveis do tipo apontador pode ser construída a
partir de qualquer tipo definido anteriormente, e deve especificar o tipo de
variável referenciada pelo apontador.
A declaração de uma variável do tipo apontador é feita colocando um * antes
do nome da variável. Assim, na declaração:
As variáveis i, j, k, m são do tipo int, f é do tipo float e d, d2 do tipo double.
Além destas variáveis de tipos elementares, são declaradas as variáveis pi, pi2
do tipo apontador para inteiro, enquanto pd e pd2 são do tipo apontador para
double.
Estruturas
de
Dados
Compostas
 

M"
6 Professora Aida Meira
Analogamente o funcionamento de um ponteiro é assim:


Esquematicamente:


Estruturas
de
Dados
Compostas
 

M"
7 Professora Aida Meira
Exemplo:
Função
Troca



Função para trocar o valor de duas variáveis inteiras:
– Void troca (int a, int b)
Essa função tem o código:
int aux;
aux = a;
a = b;
b = aux;
• Vamos agora chamar a função troca no main, onde a=5 e b=10.
• Qual é o valor de cada variável depois de chamares a função?
a = 10 e b=5 , Não! O valor fica igual.
O que a função recebeu, na realidade, não foi a variável A nem a variável B.
Ela recebeu os seus valores.
Portanto, dentro da função, realmente houve uma troca mas as variáveis locais
de cada função "morrem" quando a função termina.
Sendo assim, de volta no main, não houve alteração de valores.
Em vez de receberes o valor de cada variável, recebes o local onde esse valor
está armazenado!
Assim podes alterar directamente o seu valor e assim, se mudas o valor no sitio
onde ele está guardado, esse valor é alterado tanto dentro das funções como
fora.
Portanto mudas o cabeçalho da função para:
void swap( int * a, int * b);
Estruturas
de
Dados
Compostas
 

M"
8 Professora Aida Meira
e o código para:
int aux;
aux = *a;
*a = *b;
*b = aux;
Assim sendo, estás mesmo a alterar a "raiz" da variável e assim, no main, a
alteração mantém-se.
Tal como pode ser observado, a solução adotada consiste em passar à
função não o valor das variáveis a e b, mas sim os seus endereços. Embora
estes endereços sejam passados por valor (ou seja a função recebe uma
copia destes valores), o endereço permite à função o conhecimento da
Estruturas
de
Dados
Compostas
 

M"
9 Professora Aida Meira
posição das variáveis a e b em memoria e, deste modo, permite a
manipulação do seu conteúdo por meio de um endereçamento indireto.
Vamos observar o mapa de memória das diferentes fases que passa no
programa anterior:
Imagem 1 - Antes da chamada da função Imagem 2 - No inicio da troca
Imagem 3 - No final da troca Imagem 4 - Após o regresso ao main


DECLARAÇÃO

A declaração de uma variável do tipo ponteiro (ou apontador) consiste do tipo
base (aquele para o qual o ponteiro vai apontar), um * e o nome da variável.
A forma geral é:
tipo *nome;
ou
tipo* nome;
Exemplos:


int *contador; ponteiro para um inteiro
char *meuString; ponteiro para caracteres
float *raizQuadrada; ponteiro para real.
Estruturas
de
Dados
Compostas
 

M"
11 Professora Aida Meira
Caso especial:
void *simplesPonteiro; ponteiro genérico.
OPERADORES

Existem dois operadores especiais para ponteiros:
* indireção.
– Devolve o valor apontado pelo ponteiro.
& operador de endereço.
– Devolve o endereço na memória de seu operando.
Exemplo:


main ()
{
int *aponta;
int valor1, valor2;
valor1 = 5; // inicializa valor1 com 5
aponta = &valor1; // aponta recebe o endereço de valor1, ou seja:
passa a apontar para valor1
valor2 = *aponta; // valor2 recebe o valor apontado por aponta,
nesse caso 5, pois aponta possui como valor
o endereço de valor1
}
Estruturas
de
Dados
Compostas
 

M"
12 Professora Aida Meira
Precedência: Tanto o & como o * possuem precedência maior do que todos os
outros operadores, com exceção do menos unário, que possuem a mesma.
– int valor; int *aponta; valor = *aponta++
EXPRESSÕES

ATRIBUIÇÃO
Atribuição direta entre ponteiros passa o endereço de memória apontado por
um para o outro.
int *p1, *p2, x;
x = 4;
p1 = &x; /* p1 passa a apontar para x */
p2 = p1; /* p2 recebeu o valor de p1, que é */
/* o endereço de x, ou seja: p2 */
/* também aponta para x. */
printf ("%p", p2 ); /* imprime o endereço de x */
printf ("%i", *p2 ); /* imprime o valor apontado por */
/* p2, seja: o valor de x. */
O operador de endereço &, quando usado como operador sobre um ponteiro,
devolve o endereço ocupado por este ponteiro, não o endereço apontado por
ele.
Duas operações aritméticas são válidas com ponteiros: adição e subtração.
Estas são muito úteis com vetores.
A expressão abaixo é válida em "C":
int *p1, *p2, *p3, *p4, x=0;
p1 = &x;
p2 = p1++;
p3 = p2 + 4;
p4 = p3 - 5; /* p4 acaba tendo o mesmo valor que p1 */
/* no começo. */
Estruturas
de
Dados
Compostas
 

M"
13 Professora Aida Meira
/* Note que p1 foi incrementado e */
/* agora tem o valor (&x + 1). */
Observe que aqui as expressões *p2 e *p3 vão resultar em um erro, já que
esses ponteiros estarão apontando para áreas de memória que não estão
associadas com nenhuma variável. O único endereço de memória acessável é
o de x.
COMPARAÇÃO

Podes comparar ponteiros, para saber se um ponteiro aponta para um
endereço de memória mais alto do que outro.
Exemplo:


int *p, *q;
....
if (p < q)
printf("p aponta para um endereço menor que o de q");
É um trecho de programa perfeitamente válido em "C".
– Isto pode ser útil em testes em matrizes e vetores.
PONTEIROS
E
VETORES


Ponteiros, Vetores e Matrizes possuem uma relação muito estreita em "C”
A qual podemos aproveitar de muitas formas para escrever programas que
ninguém entende...
Em C, os elementos de um vetor são sempre guardados sequencialmente, a
uma distância fixa um do outro. Com isso, é possível facilmente passar de um
elemento a outro, percorrendo sempre uma mesma distância para frente ou
Estruturas
de
Dados
Compostas
 

M"
14 Professora Aida Meira
para trás na memória. Dessa maneira, podemos usar ponteiros e a aritmética
de ponteiros para percorrer vetores. Na verdade, vetores são ponteiros ― um
uso particular dos ponteiros.
Exemplo:


char nome[30] = "José da Silva";
char *p1, *p2;
char car;
int i;
p1 = nome; // nome sozinho é um ponteiro
// para o 1º elemento de nome[].
car = nome[3]; // Atribui 'é' a car.
car = p1[0]; // Atribui 'J' a car. Válido.
p2 = &nome[5]; // Atribui a p2 o endereço da 6ª
// posição de nome, no caso 'd'.
printf( "%s", p2); // Imprime "da Silva"...
p2 = p1; // Evidentemente válido.
p2 = p1 + 5; // Equivalente a p2 = &nome[5]
printf( "%s",(p1 + 5)); // Imprime "da Silva"...
printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!!
for (i=0; strlen(nome)- 1; i++)
{
printf ("%c", nome[i]); // Imprime 'J','o','s',etc
p2 = p1 + i;
printf ("%c", *p2); // Imprime 'J','o','s',etc
}
Acompanhe o exemplo a seguir.
Estruturas
de
Dados
Compostas
 

M"
15 Professora Aida Meira
Começamos declarando um vetor com três elementos; depois, criamos um
ponteiro para esse vetor. Mas repare que não colocamos o operador de
endereço em vetorTeste; fazemos isso porque um vetor já representa um
endereço, como você pode verificar pelo resultado da primeira chamada a
printf().
Podemos usar a sintaxe *(ptr + 1) para aceder o inteiro seguinte ao
apontado pelo ponteiro ptr. Mas, se o ponteiro aponta para o vetor, o próximo
inteiro na memória será o próximo elemento do vetor!
De fato, em C as duas formas *(ptr + n) e ptr[n] são equivalentes.
Não é necessário criar um ponteiro para usar essa sintaxe; o vetor em si já é
um ponteiro, de modo que qualquer operação com ptr será feita igualmente
com vetorTeste. Todas as formas abaixo de aceder o segundo elemento do
vetor são equivalentes:
vetorTeste[1];
*(vetorTeste + 1);
ptr[1];
*(ptr + 1)
Estruturas
de
Dados
Compostas
 

M"
16 Professora Aida Meira
Exemplo:


PONTEIROS
COMO
PARAMETROS
DE
FUNÇÕES

Comecemos por uma situação-problema: eu tenho 2 variáveis e quero trocar o
valor delas. Vamos começar com um algoritmo simples, dentro da função
main():
Estruturas
de
Dados
Compostas
 

M"
17 Professora Aida Meira
Esse exemplo funcionará exatamente como esperado: primeiramente ele
imprimirá "5 10" e depois ele imprimirá "10 5". Mas e se quisermos trocar várias
vezes o valor de duas variáveis? É muito mais conveniente criar uma função
que faça isso. Vamos fazer uma tentativa de implementação da função swap
(troca, em inglês):
Estruturas
de
Dados
Compostas
 

M"
18 Professora Aida Meira
No entanto, o que queremos não irá acontecer.
Verá que o programa imprime duas vezes "5 10". Por que isso acontece?
Lembre-se do escopo das variáveis: as variáveis a e b são locais à função
main(), e quando as passamos como argumentos para swap(), os valores são
copiados e passam a ser chamados de i e j; a troca ocorre entre i e j, de modo
que quando voltamos à função main() nada mudou.
Então como poderíamos fazer isso? Como são retornados dois valores, não
podemos usar o valor de retorno de uma função. Mas existe uma alternativa: os
ponteiros.
Estruturas
de
Dados
Compostas
 

M"
19 Professora Aida Meira
Neste exemplo, definimos a função swap() como uma função que toma como
argumentos dois ponteiros para inteiros; a função faz a troca entre os valores
apontados pelos ponteiros. Já na função main(), passamos os endereços das
variáveis para a função swap(), de modo que a função swap() possa modificar
variáveis locais de outra função. O único possível inconveniente é que, quando
usarmos a função, teremos de lembrar de colocar um & na frente das variáveis
que estivermos passando para a função.
Se pensar bem, já vimos uma função em que passamos os argumentos
precedidos de &: é a função scanf()!
Por que fazemos isso?
É simples: chamamos a função scanf() para que ela ponha nas nossas
variáveis valores digitados pelo usuário.
Essas variáveis são locais, e portanto só podem ser alteradas por outras
funções através de ponteiros!
Quando uma função recebe como parâmetros os endereços e não os valores
das variáveis, dizemos que estamos a fazer uma chamada por referência; é o
caso desse último exemplo. Quando passamos diretamente os valores das
Estruturas
de
Dados
Compostas
 

M"
20 Professora Aida Meira
variáveis para uma função, dizemos que é uma chamada por valor; foi o caso
do segundo exemplo.
PONTEIROS
PARA
FUNÇÕES

Os ponteiros para funções servem, geralmente, para passar uma função como
argumento de uma outra função.
Neste exemplo:
Veja que criamos uma função que retorna a soma dos dois inteiros a ela
fornecidos; no entanto, ela não é chamada diretamente.
Ela é chamada pela função operação, através de um ponteiro. A função main
passa a função soma como argumento para operação, e a função operação
chama essa função que lhe foi dada como argumento.
Estruturas
de
Dados
Compostas
 

M"
21 Professora Aida Meira
Note bem o terceiro argumento da função operação: ele é um ponteiro para
uma função.
Neste caso, ele foi declarado como um ponteiro para uma função que toma
dois inteiros como argumentos e retorna outro inteiro.
O * indica que estamos declarando um ponteiro, e não uma função. Os
parênteses em torno de *func são essenciais, pois sem eles o compilador
entenderia o argumento como uma função que retorna um ponteiro para um
inteiro.
A forma geral para declarar um ponteiro para uma função é:
tipo_retorno (*nome_do_ponteiro)(lista de argumentos)
Para chamar a função apontada pelo ponteiro, há duas sintaxes. A sintaxe
original é:
(*nome_do_ponteiro)(argumentos);
Se ptr é um ponteiro para uma função, faz bastante sentido que a função em si
seja chamada por *ptr. No entanto, a sintaxe mais moderna permite que
ponteiros para funções sejam chamados exatamente da mesma maneira que
funções:
nome_do_ponteiro(argumentos);
Por fim, para inicializar um ponteiro para função, não precisamos usar o
operador de endereço (ele já está implícito). Por isso, quando chamamos a
função operação, não precisamos escrever &soma.
Veja mais um exemplo — na verdade, uma extensão do exemplo
anterior:
Estruturas
de
Dados
Compostas
 

M"
22 Professora Aida Meira
Aqui, criamos mais uma função, subtracao, além de criar um outro ponteiro
para ela (uma espécie de "atalho"), menos. Na função main, referimo-nos à
função de subtração através desse atalho.
Veja também que aqui usamos a sintaxe moderna para a chamada de
ponteiros de funções, ao contrário do exemplo anterior.
Estruturas
de
Dados
Compostas
 

M"
23 Professora Aida Meira
2. Tipos
Estruturados

Na linguagem C, existem os tipos básicos (char, int, float, etc.) e seus
respetivos ponteiros que podem ser usados na declaração de variáveis. Para
estruturar dados complexos, nos quais as informações são compostas por
diversos campos, necessitamos de mecanismos que nos permitam agrupar
tipos distintos.




O
TIPO
ESTRUTURA

Em C, podemos definir um tipo de dado cujos campos são compostos de vários
valores de tipos mais simples. Para ilustrar, vamos considerar o
desenvolvimento de programas que manipulam pontos no plano cartesiano.
Cada ponto pode ser representado por suas coordenadas x e y, ambas dadas
por valores reais.
Sem um mecanismo para agrupar as duas componentes, teríamos que
representar cada ponto por duas variáveis independentes.
float x;
float y;
No entanto, deste modo, os dois valores ficam dissociados e, no caso do
programa manipular vários pontos, cabe ao programador não misturar a
coordenada x de um ponto com a coordenada y de outro.
Para facilitar este trabalho, a linguagem C oferece recursos para agruparmos
dados. Uma estrutura, em C, serve basicamente para agrupar diversas
variáveis dentro de um único contexto.
No nosso exemplo, podemos definir uma estrutura ponto que contenha as duas
variáveis.
A sintaxe para a definição de uma estrutura é mostrada abaixo:
Estruturas
de
Dados
Compostas
 

M"
24 Professora Aida Meira
Desta forma, a estrutura ponto passa a ser um tipo e podemos então declarar
variáveis deste tipo.


struct ponto p;
Esta linha de código declara p como sendo uma variável do tipo struct ponto.
Os elementos de uma estrutura podem ser acedidos através do operador de
acesso “ponto” (.). Assim, é válido escrever:


Manipulamos os elementos de uma estrutura da mesma forma que variáveis
simples.
Podemos aceder seus valores, atribuir-lhes novos valores, aceder seus
endereços, etc.


Exemplo:
Capturar e imprimir as coordenadas de um ponto.



Para exemplificar o uso de estruturas em programas, vamos considerar um
exemplo simples em que capturamos e imprimimos as coordenadas de um
ponto qualquer.


Estruturas
de
Dados
Compostas
 

M"
25 Professora Aida Meira
A variável p, definida dentro de main, é uma variável local como outra qualquer.
Quando a declaração é encontrada, aloca-se, na pilha de execução, um
espaço para seu armazenamento, isto é, um espaço suficiente para armazenar
todos os campos da estrutura (no caso, dois números reais).
Atenção que o acesso ao endereço de um campo da estrutura é feito da
mesma forma que com variáveis simples: basta escrever &(p.x), ou
simplesmente &p.x, pois o operador de acesso ao campo da estrutura tem
precedência sobre o operador “endereço de”.


PONTEIRO
PARA
ESTRUTURAS

Da mesma forma que podemos declarar variáveis do tipo estrutura:
struct ponto p;
Podemos também declarar variáveis do tipo ponteiro para estrutura:
struct ponto *pp;
Se a variável pp armazenar o endereço de uma estrutura, podemos aceder os
campos dessa estrutura indiretamente, através de seu ponteiro:
(*pp).x = 12.0;
Neste caso, os parênteses são indispensáveis, pois o operador “conteúdo de”
tem precedência menor que o operador de acesso. O acesso de campos de
estruturas é tão comum em programas C que a linguagem oferece outro
Estruturas
de
Dados
Compostas
 

M"
26 Professora Aida Meira
operador de acesso, que permite aceder campos a partir do ponteiro da
estrutura. Este operador é composto por um traço seguido de um sinal de
maior, formando uma seta (->).
Portanto, podemos reescrever a atribuição anterior fazendo:
pp->x = 12.0;
Em resumo, se temos uma variável estrutura e queremos aceder seus campos,
usamos o operador de acesso ponto (p.x); se temos uma variável ponteiro
para estrutura, usamos o operador de acesso seta (pp->x).
Seguindo o raciocínio, se temos o ponteiro e queremos aceder o endereço de
um campo, fazemos &pp->x


PASSAGEM
DE
ESTRUTURAS
PARA
FUNÇÕES

Para exemplificar a passagem de variáveis do tipo estrutura para funções,
podemos reescrever o programa simples, mostrado anteriormente, que captura
e imprime as coordenadas de um ponto qualquer. Inicialmente, podemos
pensar em escrever uma função que imprima as coordenadas do ponto. Esta
função poderia ser dada por:
void imprime (struct ponto p)
{
printf("O ponto fornecido foi: (%.2f,%.2f)n", p.x,
p.y);
}
A passagem de estruturas para funções processa-se de forma análoga à
passagem de variáveis simples, porém exige uma análise mais detalhada. Da
forma como está escrita no código acima, a função recebe uma estrutura inteira
como parâmetro.
Portanto, faz-se uma cópia de toda a estrutura e a função acede aos dados
desta cópia.
Estruturas
de
Dados
Compostas
 

M"
27 Professora Aida Meira
Existem dois pontos a serem ressaltados. Primeiro, como em toda passagem
por valor, a função não tem como alterar os valores dos elementos da estrutura
original (na função imprime isso realmente não é necessário, mas seria numa
função de leitura).
O segundo ponto diz respeito à eficiência, visto que copiar uma estrutura
inteira pode ser uma operação custosa (principalmente se a estrutura for muito
grande).
É mais conveniente passar apenas o ponteiro da estrutura, mesmo que não
seja necessário alterar os valores dos elementos dentro da função.
Desta forma, uma segunda (e mais adequada) alternativa para escrevermos a
função imprime é:


void imprime (struct ponto* pp)
{
printf("O ponto fornecido foi: (%.2f,%.2f)n", pp->x,
pp->y);
}
Podemos ainda pensar numa função para ler a hora do evento. Observamos
que, neste caso, obrigatoriamente devemos passar o ponteiro da estrutura,
caso contrário não seria possível passar ao programa principal os dados lidos:
void captura (struct ponto* pp) {
printf("Digite as coordenadas do ponto(x y): ");
scanf("%f %f", &p->x, &p->y);
}
Com estas funções, nossa função main ficaria como mostrado abaixo.
int main (void) {
struct ponto p;
captura(&p);
imprime(&p);
Estruturas
de
Dados
Compostas
 

M"
28 Professora Aida Meira
return 0;
}
Exercício:

Função para determinar a distância entre dois pontos.
Considere a implementação de uma função que tenha como valor de retorno a
distância entre dois pontos. O protótipo da função pode ser dado por:


DEFINIÇÃO
DE
“NOVOS”
TIPOS

A linguagem C permite criar nomes de tipos. Por exemplo, se escrevermos:
typedef float Real;


Podemos usar o nome Real como um mnemônico para o tipo float. O uso de
typedef é muito útil para abreviarmos nomes de tipos e para tratarmos tipos
complexos. Alguns exemplos válidos de typedef:


typedef unsigned char UChar;
typedef int* PInt;
typedef float Vetor[4];
Neste fragmento de código, definimos UChar como sendo o tipo char sem
sinal, PInt como um tipo ponteiro para int, e Vetor como um tipo que
representa um vetor de quatro elementos. A partir dessas definições, podemos
declarar variáveis usando estes mnemônicos:


Vetor v;
Estruturas
de
Dados
Compostas
 

M"
29 Professora Aida Meira
...
v[0] = 3;
...
Em geral, definimos nomes de tipos para as estruturas com as quais nossos
programas trabalham. Por exemplo, podemos escrever:


struct ponto {
float x;
float y;
};
typedef struct ponto Ponto;
Neste caso, Ponto passa a representar nossa estrutura de ponto. Também
podemos definir um nome para o tipo ponteiro para a estrutura.
typedef struct ponto *PPonto;
Podemos ainda definir mais de um nome num mesmo typedef. Os dois
typedef
anteriores poderiam ser escritos por:
typedef struct ponto Ponto, *PPonto;
A sintaxe de um typedef pode parecer confusa, mas é equivalente à da
declaração de variáveis. Por exemplo, na definição abaixo:
typedef float Vector[4];
Se omitíssemos a palavra typedef, estaríamos a declarar a variável Vector
como sendo um vetor de 4 elementos do tipo float. Com typedef, estamos a
definir um nome que representa o tipo vetor de 4 elementos float.
De maneira análoga, na definição:
Estruturas
de
Dados
Compostas
 

M"
30 Professora Aida Meira
typedef struct ponto Ponto, *PPonto;
Se omitíssemos a palavra typedef, estaríamos a declarar a variável Ponto
como sendo do tipo struct ponto e a variável PPonto como sendo do tipo
ponteiro para
struct ponto.
Por fim, salienta-se que podemos definir a estrutura e associar mnemônicos
para elas em um mesmo comando:
typedef struct ponto {
float x;
float y;
} Ponto, *PPonto;
É comum os programadores de C usarem nomes com as primeiras letras
maiúsculas na definição de tipos. Isso não é uma obrigatoriedade, apenas um
estilo de codificação.
VETORES
DE
ESTRUTURAS

Já discutimos o uso de vetores para agrupar elementos dos tipos básicos
(vetores de inteiros, por exemplo).
Nesta seção, vamos discutir o uso de vetores de estruturas, isto é, vetores
cujos elementos são estruturas. Para ilustrar a discussão, vamos considerar o
cálculo da área de um polígono plano qualquer delimitado por uma sequência
de n
pontos. A área desse polígono pode ser calculada somando-se as áreas
dos trapézios formados pelos lados do polígono e o eixo x, conforme ilustra a
Figura


Estruturas
de
Dados
Compostas
 

M"
31 Professora Aida Meira
FIGURA: Cálculo da área de um polígono
Na figura, ressaltamos a área do trapézio definido pela aresta que vai do ponto
pi ao ponto pi+1. A área desse trapézio é dada por: ( )( ) / 2 i 1 i i 1 i a # x ! x y "
y " " . Somando-se as “áreas” (algumas delas negativas) dos trapézios
definidos por todas as arestas chega-se a área do polígono (as áreas externas
ao polígono são anuladas). Se a sequência de pontos que define o polígono for
dada em sentido anti-horário, chega-se a uma “área” de valor negativo.
Neste caso, a área do polígono é o valor absoluto do resultado da soma.
Um vetor de estruturas pode ser usado para definir um polígono. O polígono
passa a ser representado por uma sequência de pontos. Podemos, então,
escrever uma função para calcular a área de um polígono, dados o número de
pontos e o vetor de pontos que o representa. Uma implementação dessa
função é mostrada abaixo.
Um exemplo de uso dessa função é mostrado no código abaixo:
Estruturas
de
Dados
Compostas
 

M"
32 Professora Aida Meira
int main (void){
Ponto p[3] = {{1.0,1.0},{5.0,1.0},{4.0,3.0}};
printf("area = %fn",area (3,p));
return 0;
}
Exercício:

Altere o programa acima para capturar do teclado o número de pontos que
delimitam o polígono. O programa deve, então, alocar dinamicamente o vetor
de pontos, capturar as coordenadas dos pontos e, chamando a função área,
exibir o valor da área.


VETORES
DE
PONTEIROS
PARA
ESTRUTURAS

Da mesma forma que podemos declarar vetores de estruturas, podemos
também declarar vetores de ponteiros para estruturas. O uso de vetores de
ponteiros é útil quando temos que tratar um conjunto elementos complexos.
Para ilustrar o uso de estruturas complexas, consideremos um exemplo em que
desejamos armazenar uma tabela com dados de alunos.
Podemos organizar os dados dos alunos em um vetor. Para cada aluno, vamos
supor que sejam necessárias as seguintes informações:
• nome:
cadeia
com
até
80
caracteres

• matricula:
número
inteiro

• endereço:
cadeia
com
até
120
caracteres

• telefone:
cadeia
com
até
20
caracteres
Para estruturar esses dados, podemos definir um tipo que representa os dados
de um aluno:
struct aluno {
char nome[81];
Estruturas
de
Dados
Compostas
 

M"
33 Professora Aida Meira
int mat;
char end[121];
char tel[21];
};
typedef struct aluno Aluno;
Vamos montar a tabela de alunos usando um vetor global com um número
máximo de alunos. Uma primeira opção é declarar um vetor de estruturas:
#define MAX 100
Aluno tab[MAX];
Desta forma, podemos armazenar nos elementos do vetor os dados dos alunos
que queremos organizar. Seria válido, por exemplo, uma atribuição do tipo:
...
tab[i].mat = 9912222;
...
No entanto, o uso de vetores de estruturas tem, neste caso, uma grande
desvantagem.
O tipo Aluno definido acima ocupa pelo menos 227 (=81+4+121+21) bytes1. A
declaração de um vetor desta estrutura representa um desperdício significativo
de memória, pois provavelmente estamos a armazenar um número de alunos
bem inferior ao máximo estimado. Para contornar este problema, podemos
trabalhar com um vetor de ponteiros.
typedef struct aluno *PAluno;
#define MAX 100
PAluno tab[MAX];
Assim, cada elemento do vetor ocupa apenas o espaço necessário para
armazenar um ponteiro. Quando precisarmos alocar os dados de um aluno
Estruturas
de
Dados
Compostas
 

M"
34 Professora Aida Meira
numa determinada posição do vetor, alocamos dinamicamente a estrutura
Aluno e guardamos seu endereço no vetor de ponteiros.
Considerando o vetor de ponteiros declarado acima como uma variável global,
podemos ilustrar a implementação de algumas funcionalidades para manipular
nossa tabela de alunos. Inicialmente, vamos considerar uma função de
inicialização. Uma posição do vetor estará vazia, isto é, disponível para
armazenar informações de um novo aluno, se o valor do seu elemento for o
ponteiro nulo. Portanto, numa função de inicialização, podemos atribuir NULL a
todos os elementos da tabela, significando que temos, a princípio, uma tabela
vazia.
void inicializa (void)
{
int i;
for (i=0; i<MAX; i++)
tab[i] = NULL;
}
Uma segunda funcionalidade que podemos prever armazena os dados de um
novo aluno numa posição do vetor. Vamos considerar que os dados serão
fornecidos via teclado e que uma posição onde os dados serão armazenados
será passada para a função. Se a posição da tabela estiver vazia, devemos
alocar uma nova estrutura; caso contrário, atualizamos a estrutura já apontada
pelo ponteiro.
void preenche (int i)
{
if (tab[i]==NULL)
tab[i] = (PAluno)malloc(sizeof(Aluno));
printf("Entre com o nome:");
scanf(" %80[^n]", tab[i]->nome);
Estruturas
de
Dados
Compostas
 

M"
35 Professora Aida Meira
printf("Entre com a matricula:");
scanf("%d", &tab[i]->mat);
printf("Entre com o endereco:");
scanf(" %120[^n]", tab[i]->end);
printf("Entre com o telefone:");
scanf(" %20[^n]", tab[i]->tel);
Podemos também prever uma função para remover os dados de um aluno da
tabela. Vamos considerar que a posição da tabela a ser liberada será passada
para a função:
void remove (int i) {
if (tab[i] != NULL) {
free(tab[i]);
tab[i] = NULL;
}
}
Para consultarmos os dados, vamos considerar uma função que imprime os
dados armazenados numa determinada posição do vetor:
void imprime (int i) {
if (tab[i] != NULL) {
printf("Nome: %sn”, tab[i]->nome);
printf("Matrícula: %dn”, tab[i]->mat);
printf("Endereço: %sn”, tab[i]->end);
printf("Telefone: %sn”, tab[i]->tel);
}
}
Estruturas
de
Dados
Compostas
 

M"
36 Professora Aida Meira
Por fim, podemos implementar uma função que imprima os dados de todos os
alunos da tabela:
void imprime_tudo (void) {
int i;
for (i=0; i<MAX; i++)
imprime(i);
}
Exercício:

Faça um programa que utilize as funções da tabela de alunos escritas acima.
Exercício:

Re-escreva as funções acima sem usar uma variável global.
Sugestão: Crie um tipo Tabela e faça as funções receberem este tipo como
primeiro parâmetro.
Estruturas
de
Dados
Compostas
 

M"
37 Professora Aida Meira
Estruturas
de
Dados
Compostas
 

M"
38 Professora Aida Meira
EXERCICIOS
Estruturas
de
Dados
Compostas
 

M"
39 Professora Aida Meira

Mais conteúdo relacionado

Semelhante a document.onl_manual-psi-m5.pdf

095 A 134 Material Auxiliar Para Curso AvançAdo I Msp430
095 A 134   Material Auxiliar Para Curso AvançAdo I Msp430095 A 134   Material Auxiliar Para Curso AvançAdo I Msp430
095 A 134 Material Auxiliar Para Curso AvançAdo I Msp430Texas Instruments
 
8 ponteiros, ponteiros e vetores e alocacao dinamica de memoria
8   ponteiros,  ponteiros e vetores e alocacao dinamica de memoria8   ponteiros,  ponteiros e vetores e alocacao dinamica de memoria
8 ponteiros, ponteiros e vetores e alocacao dinamica de memoriaRicardo Bolanho
 
Estrutura de Dados - Aula 03 - Ponteiros e Funções
Estrutura de Dados - Aula 03 - Ponteiros e FunçõesEstrutura de Dados - Aula 03 - Ponteiros e Funções
Estrutura de Dados - Aula 03 - Ponteiros e FunçõesLeinylson Fontinele
 
Aula c++ estruturas de dados
Aula c++   estruturas de dadosAula c++   estruturas de dados
Aula c++ estruturas de dadosJean Martina
 
Vetores e Matrizes em C.
Vetores e Matrizes em C.Vetores e Matrizes em C.
Vetores e Matrizes em C.SchoolByte
 
Algoritmos e Estrutura de Dados - Aula 05
Algoritmos e Estrutura de Dados - Aula 05Algoritmos e Estrutura de Dados - Aula 05
Algoritmos e Estrutura de Dados - Aula 05thomasdacosta
 
Algoritmo e Complexidade - texto Aula1.docx
Algoritmo e Complexidade - texto Aula1.docxAlgoritmo e Complexidade - texto Aula1.docx
Algoritmo e Complexidade - texto Aula1.docxLdiaSilva39
 
Laboratório de Programação II: Uso do ponteiro void *
Laboratório de Programação II: Uso do ponteiro void *Laboratório de Programação II: Uso do ponteiro void *
Laboratório de Programação II: Uso do ponteiro void *Alex Camargo
 
Utilizando ponteiros em C.
Utilizando ponteiros em C.Utilizando ponteiros em C.
Utilizando ponteiros em C.SchoolByte
 
Tecnicas programacao i_c_p4
Tecnicas programacao i_c_p4Tecnicas programacao i_c_p4
Tecnicas programacao i_c_p4D M
 
3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...
3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...
3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...Manuel Menezes de Sequeira
 
Tipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxoTipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxoDenis L Presciliano
 
Tipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxoTipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxoDenis L Presciliano
 
Aula04 ponteiros e conversao
Aula04   ponteiros e conversaoAula04   ponteiros e conversao
Aula04 ponteiros e conversaoYuri Passos
 

Semelhante a document.onl_manual-psi-m5.pdf (20)

095 A 134 Material Auxiliar Para Curso AvançAdo I Msp430
095 A 134   Material Auxiliar Para Curso AvançAdo I Msp430095 A 134   Material Auxiliar Para Curso AvançAdo I Msp430
095 A 134 Material Auxiliar Para Curso AvançAdo I Msp430
 
8 ponteiros, ponteiros e vetores e alocacao dinamica de memoria
8   ponteiros,  ponteiros e vetores e alocacao dinamica de memoria8   ponteiros,  ponteiros e vetores e alocacao dinamica de memoria
8 ponteiros, ponteiros e vetores e alocacao dinamica de memoria
 
Estrutura de Dados - Aula 03 - Ponteiros e Funções
Estrutura de Dados - Aula 03 - Ponteiros e FunçõesEstrutura de Dados - Aula 03 - Ponteiros e Funções
Estrutura de Dados - Aula 03 - Ponteiros e Funções
 
Aula c++ estruturas de dados
Aula c++   estruturas de dadosAula c++   estruturas de dados
Aula c++ estruturas de dados
 
Pesquisa ppi 2
Pesquisa ppi 2Pesquisa ppi 2
Pesquisa ppi 2
 
Aula apontadores
Aula apontadoresAula apontadores
Aula apontadores
 
Vetores e Matrizes em C.
Vetores e Matrizes em C.Vetores e Matrizes em C.
Vetores e Matrizes em C.
 
Algoritmos e Estrutura de Dados - Aula 05
Algoritmos e Estrutura de Dados - Aula 05Algoritmos e Estrutura de Dados - Aula 05
Algoritmos e Estrutura de Dados - Aula 05
 
Unidade04
Unidade04Unidade04
Unidade04
 
Algoritmo e Complexidade - texto Aula1.docx
Algoritmo e Complexidade - texto Aula1.docxAlgoritmo e Complexidade - texto Aula1.docx
Algoritmo e Complexidade - texto Aula1.docx
 
Algoritmos
AlgoritmosAlgoritmos
Algoritmos
 
Laboratório de Programação II: Uso do ponteiro void *
Laboratório de Programação II: Uso do ponteiro void *Laboratório de Programação II: Uso do ponteiro void *
Laboratório de Programação II: Uso do ponteiro void *
 
Utilizando ponteiros em C.
Utilizando ponteiros em C.Utilizando ponteiros em C.
Utilizando ponteiros em C.
 
Tecnicas programacao i_c_p4
Tecnicas programacao i_c_p4Tecnicas programacao i_c_p4
Tecnicas programacao i_c_p4
 
3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...
3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...
3. Funções/repórteres e listas em Snap!; Utilização de variáveis – Fundamento...
 
Cap 2
Cap 2Cap 2
Cap 2
 
Cap 2
Cap 2Cap 2
Cap 2
 
Tipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxoTipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxo
 
Tipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxoTipos, literais, operadoes e controle de fluxo
Tipos, literais, operadoes e controle de fluxo
 
Aula04 ponteiros e conversao
Aula04   ponteiros e conversaoAula04   ponteiros e conversao
Aula04 ponteiros e conversao
 

Último

análise de redação completa - Dissertação
análise de redação completa - Dissertaçãoanálise de redação completa - Dissertação
análise de redação completa - DissertaçãoMaiteFerreira4
 
CRUZADINHA - Leitura e escrita dos números
CRUZADINHA   -   Leitura e escrita dos números CRUZADINHA   -   Leitura e escrita dos números
CRUZADINHA - Leitura e escrita dos números Mary Alvarenga
 
Ficha de trabalho com palavras- simples e complexas.pdf
Ficha de trabalho com palavras- simples e complexas.pdfFicha de trabalho com palavras- simples e complexas.pdf
Ficha de trabalho com palavras- simples e complexas.pdfFtimaMoreira35
 
o ciclo do contato Jorge Ponciano Ribeiro.pdf
o ciclo do contato Jorge Ponciano Ribeiro.pdfo ciclo do contato Jorge Ponciano Ribeiro.pdf
o ciclo do contato Jorge Ponciano Ribeiro.pdfCamillaBrito19
 
ATIVIDADE PARA ENTENDER -Pizzaria dos Descritores
ATIVIDADE PARA ENTENDER -Pizzaria dos DescritoresATIVIDADE PARA ENTENDER -Pizzaria dos Descritores
ATIVIDADE PARA ENTENDER -Pizzaria dos DescritoresAnaCarinaKucharski1
 
Manual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envioManual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envioManuais Formação
 
Dicionário de Genealogia, autor Gilber Rubim Rangel
Dicionário de Genealogia, autor Gilber Rubim RangelDicionário de Genealogia, autor Gilber Rubim Rangel
Dicionário de Genealogia, autor Gilber Rubim RangelGilber Rubim Rangel
 
Libras Jogo da memória em LIBRAS Memoria
Libras Jogo da memória em LIBRAS MemoriaLibras Jogo da memória em LIBRAS Memoria
Libras Jogo da memória em LIBRAS Memorialgrecchi
 
VARIEDADES LINGUÍSTICAS - 1. pptx
VARIEDADES        LINGUÍSTICAS - 1. pptxVARIEDADES        LINGUÍSTICAS - 1. pptx
VARIEDADES LINGUÍSTICAS - 1. pptxMarlene Cunhada
 
PRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdf
PRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdfPRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdf
PRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdfprofesfrancleite
 
"É melhor praticar para a nota" - Como avaliar comportamentos em contextos de...
"É melhor praticar para a nota" - Como avaliar comportamentos em contextos de..."É melhor praticar para a nota" - Como avaliar comportamentos em contextos de...
"É melhor praticar para a nota" - Como avaliar comportamentos em contextos de...Rosalina Simão Nunes
 
ENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdf
ENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdfENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdf
ENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdfLeloIurk1
 
A QUATRO MÃOS - MARILDA CASTANHA . pdf
A QUATRO MÃOS  -  MARILDA CASTANHA . pdfA QUATRO MÃOS  -  MARILDA CASTANHA . pdf
A QUATRO MÃOS - MARILDA CASTANHA . pdfAna Lemos
 
COMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕES
COMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕESCOMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕES
COMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕESEduardaReis50
 
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...azulassessoria9
 
Rota das Ribeiras Camp, Projeto Nós Propomos!
Rota das Ribeiras Camp, Projeto Nós Propomos!Rota das Ribeiras Camp, Projeto Nós Propomos!
Rota das Ribeiras Camp, Projeto Nós Propomos!Ilda Bicacro
 
DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...
DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...
DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...IsabelPereira2010
 
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...azulassessoria9
 
Bullying - Atividade com caça- palavras
Bullying   - Atividade com  caça- palavrasBullying   - Atividade com  caça- palavras
Bullying - Atividade com caça- palavrasMary Alvarenga
 

Último (20)

análise de redação completa - Dissertação
análise de redação completa - Dissertaçãoanálise de redação completa - Dissertação
análise de redação completa - Dissertação
 
CRUZADINHA - Leitura e escrita dos números
CRUZADINHA   -   Leitura e escrita dos números CRUZADINHA   -   Leitura e escrita dos números
CRUZADINHA - Leitura e escrita dos números
 
Ficha de trabalho com palavras- simples e complexas.pdf
Ficha de trabalho com palavras- simples e complexas.pdfFicha de trabalho com palavras- simples e complexas.pdf
Ficha de trabalho com palavras- simples e complexas.pdf
 
o ciclo do contato Jorge Ponciano Ribeiro.pdf
o ciclo do contato Jorge Ponciano Ribeiro.pdfo ciclo do contato Jorge Ponciano Ribeiro.pdf
o ciclo do contato Jorge Ponciano Ribeiro.pdf
 
ATIVIDADE PARA ENTENDER -Pizzaria dos Descritores
ATIVIDADE PARA ENTENDER -Pizzaria dos DescritoresATIVIDADE PARA ENTENDER -Pizzaria dos Descritores
ATIVIDADE PARA ENTENDER -Pizzaria dos Descritores
 
Manual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envioManual da CPSA_1_Agir com Autonomia para envio
Manual da CPSA_1_Agir com Autonomia para envio
 
CINEMATICA DE LOS MATERIALES Y PARTICULA
CINEMATICA DE LOS MATERIALES Y PARTICULACINEMATICA DE LOS MATERIALES Y PARTICULA
CINEMATICA DE LOS MATERIALES Y PARTICULA
 
Dicionário de Genealogia, autor Gilber Rubim Rangel
Dicionário de Genealogia, autor Gilber Rubim RangelDicionário de Genealogia, autor Gilber Rubim Rangel
Dicionário de Genealogia, autor Gilber Rubim Rangel
 
Libras Jogo da memória em LIBRAS Memoria
Libras Jogo da memória em LIBRAS MemoriaLibras Jogo da memória em LIBRAS Memoria
Libras Jogo da memória em LIBRAS Memoria
 
VARIEDADES LINGUÍSTICAS - 1. pptx
VARIEDADES        LINGUÍSTICAS - 1. pptxVARIEDADES        LINGUÍSTICAS - 1. pptx
VARIEDADES LINGUÍSTICAS - 1. pptx
 
PRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdf
PRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdfPRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdf
PRÉDIOS HISTÓRICOS DE ASSARÉ Prof. Francisco Leite.pdf
 
"É melhor praticar para a nota" - Como avaliar comportamentos em contextos de...
"É melhor praticar para a nota" - Como avaliar comportamentos em contextos de..."É melhor praticar para a nota" - Como avaliar comportamentos em contextos de...
"É melhor praticar para a nota" - Como avaliar comportamentos em contextos de...
 
ENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdf
ENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdfENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdf
ENSINO RELIGIOSO 7º ANO INOVE NA ESCOLA.pdf
 
A QUATRO MÃOS - MARILDA CASTANHA . pdf
A QUATRO MÃOS  -  MARILDA CASTANHA . pdfA QUATRO MÃOS  -  MARILDA CASTANHA . pdf
A QUATRO MÃOS - MARILDA CASTANHA . pdf
 
COMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕES
COMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕESCOMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕES
COMPETÊNCIA 4 NO ENEM: O TEXTO E SUAS AMARRACÕES
 
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: LEITURA DE IMAGENS, GRÁFICOS E MA...
 
Rota das Ribeiras Camp, Projeto Nós Propomos!
Rota das Ribeiras Camp, Projeto Nós Propomos!Rota das Ribeiras Camp, Projeto Nós Propomos!
Rota das Ribeiras Camp, Projeto Nós Propomos!
 
DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...
DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...
DeClara n.º 75 Abril 2024 - O Jornal digital do Agrupamento de Escolas Clara ...
 
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...
PROVA - ESTUDO CONTEMPORÂNEO E TRANSVERSAL: COMUNICAÇÃO ASSERTIVA E INTERPESS...
 
Bullying - Atividade com caça- palavras
Bullying   - Atividade com  caça- palavrasBullying   - Atividade com  caça- palavras
Bullying - Atividade com caça- palavras
 

document.onl_manual-psi-m5.pdf

  • 1. Disciplina: Programação de Sistemas Informáticos Ano Letivo 2011/2012 Aida Meira Curso Profissional de Técnico de Gestão e Programação de Sistemas Informáticos Módulo V Estrutura de Dados Composta
  • 2. Estruturas
de
Dados
Compostas
 
 M" 2 Professora Aida Meira INDICE 
 1.
 Apontadores..................................................................................................3
 A memória ........................................................................................................3
 Apontadores .....................................................................................................5
 Declaração .....................................................................................................10
 Operadores ....................................................................................................11
 Expressões.....................................................................................................12
 Comparação...................................................................................................13
 Ponteiros e vetores ........................................................................................13
 Ponteiros como parametros de funções.........................................................16
 Ponteiros para funções ..................................................................................20
 2.
 Tipos Estruturados......................................................................................23
 O tipo estrutura...............................................................................................23
 Ponteiro para estruturas.................................................................................25
 Passagem de estruturas para funções...........................................................26
 Definição de “novos” tipos..............................................................................28
 Vetores de estruturas .....................................................................................30
 Vetores de ponteiros para estruturas.............................................................32

  • 3. Estruturas
de
Dados
Compostas
 
 M" 3 Professora Aida Meira 1. Apontadores
 A
MEMÓRIA
 A memória de um computador encontra-se organizada em células ou palavras de memória individuais. Cada palavra de memória é referenciada por um endereço e armazena um dado conteúdo. Designa-se por “número de bits da arquitetura” o número máximo de bits que um processador ´e capaz de ler num único acesso à memória. Cada palavra de memória de referência de um processador tem em geral um número de bits idêntico ao número de bits da arquitetura. 
 
 
 
 DOUBLE FLOAT i=
2450 k=113 j=11331 F=225.345 22.5E+14 5 INT
  • 4. Estruturas
de
Dados
Compostas
 
 M" 4 Professora Aida Meira Admite-se aqui que a palavra de memória e o tipo inteiro são representados por 32 bits. De acordo com a figura, durante a compilação foram atribuídos as variáveis i, j, k, f os endereços 1002,1005, 1006 e 1004, respetivamente, enquanto a variável d foi atribuído o endereço 1007. Note-se que, com exceção do tipo double, cada variável tem uma representação interna de 32 bits, ocupando por isso apenas um endereço de memória. A variável d, de tipo double, tem uma representação interna de 64 bits, exigindo por isso duas palavras de memória: os endereços 1007 e 1008. Na figura encontram-se representados outras posições de memória, provavelmente ocupadas por outras variáveis, e cujo conteúdo é desconhecido do programador.
  • 5. Estruturas
de
Dados
Compostas
 
 M" 5 Professora Aida Meira APONTADORES
 Um ponteiro é uma variável que contém um endereço de memória, normalmente referenciando a posição de uma outra variável. (Schildt-1996) Um apontador é uma variável cujo conteúdo é um endereço de outra posição de memória. A declaração de variáveis do tipo apontador pode ser construída a partir de qualquer tipo definido anteriormente, e deve especificar o tipo de variável referenciada pelo apontador. A declaração de uma variável do tipo apontador é feita colocando um * antes do nome da variável. Assim, na declaração: As variáveis i, j, k, m são do tipo int, f é do tipo float e d, d2 do tipo double. Além destas variáveis de tipos elementares, são declaradas as variáveis pi, pi2 do tipo apontador para inteiro, enquanto pd e pd2 são do tipo apontador para double.
  • 6. Estruturas
de
Dados
Compostas
 
 M" 6 Professora Aida Meira Analogamente o funcionamento de um ponteiro é assim: 
 Esquematicamente: 

  • 7. Estruturas
de
Dados
Compostas
 
 M" 7 Professora Aida Meira Exemplo:
Função
Troca
 
 Função para trocar o valor de duas variáveis inteiras: – Void troca (int a, int b) Essa função tem o código: int aux; aux = a; a = b; b = aux; • Vamos agora chamar a função troca no main, onde a=5 e b=10. • Qual é o valor de cada variável depois de chamares a função? a = 10 e b=5 , Não! O valor fica igual. O que a função recebeu, na realidade, não foi a variável A nem a variável B. Ela recebeu os seus valores. Portanto, dentro da função, realmente houve uma troca mas as variáveis locais de cada função "morrem" quando a função termina. Sendo assim, de volta no main, não houve alteração de valores. Em vez de receberes o valor de cada variável, recebes o local onde esse valor está armazenado! Assim podes alterar directamente o seu valor e assim, se mudas o valor no sitio onde ele está guardado, esse valor é alterado tanto dentro das funções como fora. Portanto mudas o cabeçalho da função para: void swap( int * a, int * b);
  • 8. Estruturas
de
Dados
Compostas
 
 M" 8 Professora Aida Meira e o código para: int aux; aux = *a; *a = *b; *b = aux; Assim sendo, estás mesmo a alterar a "raiz" da variável e assim, no main, a alteração mantém-se. Tal como pode ser observado, a solução adotada consiste em passar à função não o valor das variáveis a e b, mas sim os seus endereços. Embora estes endereços sejam passados por valor (ou seja a função recebe uma copia destes valores), o endereço permite à função o conhecimento da
  • 9. Estruturas
de
Dados
Compostas
 
 M" 9 Professora Aida Meira posição das variáveis a e b em memoria e, deste modo, permite a manipulação do seu conteúdo por meio de um endereçamento indireto. Vamos observar o mapa de memória das diferentes fases que passa no programa anterior: Imagem 1 - Antes da chamada da função Imagem 2 - No inicio da troca
  • 10. Imagem 3 - No final da troca Imagem 4 - Após o regresso ao main 
 DECLARAÇÃO
 A declaração de uma variável do tipo ponteiro (ou apontador) consiste do tipo base (aquele para o qual o ponteiro vai apontar), um * e o nome da variável. A forma geral é: tipo *nome; ou tipo* nome; Exemplos:

 int *contador; ponteiro para um inteiro char *meuString; ponteiro para caracteres float *raizQuadrada; ponteiro para real.
  • 11. Estruturas
de
Dados
Compostas
 
 M" 11 Professora Aida Meira Caso especial: void *simplesPonteiro; ponteiro genérico. OPERADORES
 Existem dois operadores especiais para ponteiros: * indireção. – Devolve o valor apontado pelo ponteiro. & operador de endereço. – Devolve o endereço na memória de seu operando. Exemplo:

 main () { int *aponta; int valor1, valor2; valor1 = 5; // inicializa valor1 com 5 aponta = &valor1; // aponta recebe o endereço de valor1, ou seja: passa a apontar para valor1 valor2 = *aponta; // valor2 recebe o valor apontado por aponta, nesse caso 5, pois aponta possui como valor o endereço de valor1 }
  • 12. Estruturas
de
Dados
Compostas
 
 M" 12 Professora Aida Meira Precedência: Tanto o & como o * possuem precedência maior do que todos os outros operadores, com exceção do menos unário, que possuem a mesma. – int valor; int *aponta; valor = *aponta++ EXPRESSÕES
 ATRIBUIÇÃO Atribuição direta entre ponteiros passa o endereço de memória apontado por um para o outro. int *p1, *p2, x; x = 4; p1 = &x; /* p1 passa a apontar para x */ p2 = p1; /* p2 recebeu o valor de p1, que é */ /* o endereço de x, ou seja: p2 */ /* também aponta para x. */ printf ("%p", p2 ); /* imprime o endereço de x */ printf ("%i", *p2 ); /* imprime o valor apontado por */ /* p2, seja: o valor de x. */ O operador de endereço &, quando usado como operador sobre um ponteiro, devolve o endereço ocupado por este ponteiro, não o endereço apontado por ele. Duas operações aritméticas são válidas com ponteiros: adição e subtração. Estas são muito úteis com vetores. A expressão abaixo é válida em "C": int *p1, *p2, *p3, *p4, x=0; p1 = &x; p2 = p1++; p3 = p2 + 4; p4 = p3 - 5; /* p4 acaba tendo o mesmo valor que p1 */ /* no começo. */
  • 13. Estruturas
de
Dados
Compostas
 
 M" 13 Professora Aida Meira /* Note que p1 foi incrementado e */ /* agora tem o valor (&x + 1). */ Observe que aqui as expressões *p2 e *p3 vão resultar em um erro, já que esses ponteiros estarão apontando para áreas de memória que não estão associadas com nenhuma variável. O único endereço de memória acessável é o de x. COMPARAÇÃO
 Podes comparar ponteiros, para saber se um ponteiro aponta para um endereço de memória mais alto do que outro. Exemplo:

 int *p, *q; .... if (p < q) printf("p aponta para um endereço menor que o de q"); É um trecho de programa perfeitamente válido em "C". – Isto pode ser útil em testes em matrizes e vetores. PONTEIROS
E
VETORES

 Ponteiros, Vetores e Matrizes possuem uma relação muito estreita em "C” A qual podemos aproveitar de muitas formas para escrever programas que ninguém entende... Em C, os elementos de um vetor são sempre guardados sequencialmente, a uma distância fixa um do outro. Com isso, é possível facilmente passar de um elemento a outro, percorrendo sempre uma mesma distância para frente ou
  • 14. Estruturas
de
Dados
Compostas
 
 M" 14 Professora Aida Meira para trás na memória. Dessa maneira, podemos usar ponteiros e a aritmética de ponteiros para percorrer vetores. Na verdade, vetores são ponteiros ― um uso particular dos ponteiros. Exemplo:

 char nome[30] = "José da Silva"; char *p1, *p2; char car; int i; p1 = nome; // nome sozinho é um ponteiro // para o 1º elemento de nome[]. car = nome[3]; // Atribui 'é' a car. car = p1[0]; // Atribui 'J' a car. Válido. p2 = &nome[5]; // Atribui a p2 o endereço da 6ª // posição de nome, no caso 'd'. printf( "%s", p2); // Imprime "da Silva"... p2 = p1; // Evidentemente válido. p2 = p1 + 5; // Equivalente a p2 = &nome[5] printf( "%s",(p1 + 5)); // Imprime "da Silva"... printf( "%s",(p1 + 20)); // Cuidado: Imprime lixo!! for (i=0; strlen(nome)- 1; i++) { printf ("%c", nome[i]); // Imprime 'J','o','s',etc p2 = p1 + i; printf ("%c", *p2); // Imprime 'J','o','s',etc } Acompanhe o exemplo a seguir.
  • 15. Estruturas
de
Dados
Compostas
 
 M" 15 Professora Aida Meira Começamos declarando um vetor com três elementos; depois, criamos um ponteiro para esse vetor. Mas repare que não colocamos o operador de endereço em vetorTeste; fazemos isso porque um vetor já representa um endereço, como você pode verificar pelo resultado da primeira chamada a printf(). Podemos usar a sintaxe *(ptr + 1) para aceder o inteiro seguinte ao apontado pelo ponteiro ptr. Mas, se o ponteiro aponta para o vetor, o próximo inteiro na memória será o próximo elemento do vetor! De fato, em C as duas formas *(ptr + n) e ptr[n] são equivalentes. Não é necessário criar um ponteiro para usar essa sintaxe; o vetor em si já é um ponteiro, de modo que qualquer operação com ptr será feita igualmente com vetorTeste. Todas as formas abaixo de aceder o segundo elemento do vetor são equivalentes: vetorTeste[1]; *(vetorTeste + 1); ptr[1]; *(ptr + 1)
  • 16. Estruturas
de
Dados
Compostas
 
 M" 16 Professora Aida Meira Exemplo:

 PONTEIROS
COMO
PARAMETROS
DE
FUNÇÕES
 Comecemos por uma situação-problema: eu tenho 2 variáveis e quero trocar o valor delas. Vamos começar com um algoritmo simples, dentro da função main():
  • 17. Estruturas
de
Dados
Compostas
 
 M" 17 Professora Aida Meira Esse exemplo funcionará exatamente como esperado: primeiramente ele imprimirá "5 10" e depois ele imprimirá "10 5". Mas e se quisermos trocar várias vezes o valor de duas variáveis? É muito mais conveniente criar uma função que faça isso. Vamos fazer uma tentativa de implementação da função swap (troca, em inglês):
  • 18. Estruturas
de
Dados
Compostas
 
 M" 18 Professora Aida Meira No entanto, o que queremos não irá acontecer. Verá que o programa imprime duas vezes "5 10". Por que isso acontece? Lembre-se do escopo das variáveis: as variáveis a e b são locais à função main(), e quando as passamos como argumentos para swap(), os valores são copiados e passam a ser chamados de i e j; a troca ocorre entre i e j, de modo que quando voltamos à função main() nada mudou. Então como poderíamos fazer isso? Como são retornados dois valores, não podemos usar o valor de retorno de uma função. Mas existe uma alternativa: os ponteiros.
  • 19. Estruturas
de
Dados
Compostas
 
 M" 19 Professora Aida Meira Neste exemplo, definimos a função swap() como uma função que toma como argumentos dois ponteiros para inteiros; a função faz a troca entre os valores apontados pelos ponteiros. Já na função main(), passamos os endereços das variáveis para a função swap(), de modo que a função swap() possa modificar variáveis locais de outra função. O único possível inconveniente é que, quando usarmos a função, teremos de lembrar de colocar um & na frente das variáveis que estivermos passando para a função. Se pensar bem, já vimos uma função em que passamos os argumentos precedidos de &: é a função scanf()! Por que fazemos isso? É simples: chamamos a função scanf() para que ela ponha nas nossas variáveis valores digitados pelo usuário. Essas variáveis são locais, e portanto só podem ser alteradas por outras funções através de ponteiros! Quando uma função recebe como parâmetros os endereços e não os valores das variáveis, dizemos que estamos a fazer uma chamada por referência; é o caso desse último exemplo. Quando passamos diretamente os valores das
  • 20. Estruturas
de
Dados
Compostas
 
 M" 20 Professora Aida Meira variáveis para uma função, dizemos que é uma chamada por valor; foi o caso do segundo exemplo. PONTEIROS
PARA
FUNÇÕES
 Os ponteiros para funções servem, geralmente, para passar uma função como argumento de uma outra função. Neste exemplo: Veja que criamos uma função que retorna a soma dos dois inteiros a ela fornecidos; no entanto, ela não é chamada diretamente. Ela é chamada pela função operação, através de um ponteiro. A função main passa a função soma como argumento para operação, e a função operação chama essa função que lhe foi dada como argumento.
  • 21. Estruturas
de
Dados
Compostas
 
 M" 21 Professora Aida Meira Note bem o terceiro argumento da função operação: ele é um ponteiro para uma função. Neste caso, ele foi declarado como um ponteiro para uma função que toma dois inteiros como argumentos e retorna outro inteiro. O * indica que estamos declarando um ponteiro, e não uma função. Os parênteses em torno de *func são essenciais, pois sem eles o compilador entenderia o argumento como uma função que retorna um ponteiro para um inteiro. A forma geral para declarar um ponteiro para uma função é: tipo_retorno (*nome_do_ponteiro)(lista de argumentos) Para chamar a função apontada pelo ponteiro, há duas sintaxes. A sintaxe original é: (*nome_do_ponteiro)(argumentos); Se ptr é um ponteiro para uma função, faz bastante sentido que a função em si seja chamada por *ptr. No entanto, a sintaxe mais moderna permite que ponteiros para funções sejam chamados exatamente da mesma maneira que funções: nome_do_ponteiro(argumentos); Por fim, para inicializar um ponteiro para função, não precisamos usar o operador de endereço (ele já está implícito). Por isso, quando chamamos a função operação, não precisamos escrever &soma. Veja mais um exemplo — na verdade, uma extensão do exemplo anterior:
  • 22. Estruturas
de
Dados
Compostas
 
 M" 22 Professora Aida Meira Aqui, criamos mais uma função, subtracao, além de criar um outro ponteiro para ela (uma espécie de "atalho"), menos. Na função main, referimo-nos à função de subtração através desse atalho. Veja também que aqui usamos a sintaxe moderna para a chamada de ponteiros de funções, ao contrário do exemplo anterior.
  • 23. Estruturas
de
Dados
Compostas
 
 M" 23 Professora Aida Meira 2. Tipos
Estruturados
 Na linguagem C, existem os tipos básicos (char, int, float, etc.) e seus respetivos ponteiros que podem ser usados na declaração de variáveis. Para estruturar dados complexos, nos quais as informações são compostas por diversos campos, necessitamos de mecanismos que nos permitam agrupar tipos distintos. 
 
 O
TIPO
ESTRUTURA
 Em C, podemos definir um tipo de dado cujos campos são compostos de vários valores de tipos mais simples. Para ilustrar, vamos considerar o desenvolvimento de programas que manipulam pontos no plano cartesiano. Cada ponto pode ser representado por suas coordenadas x e y, ambas dadas por valores reais. Sem um mecanismo para agrupar as duas componentes, teríamos que representar cada ponto por duas variáveis independentes. float x; float y; No entanto, deste modo, os dois valores ficam dissociados e, no caso do programa manipular vários pontos, cabe ao programador não misturar a coordenada x de um ponto com a coordenada y de outro. Para facilitar este trabalho, a linguagem C oferece recursos para agruparmos dados. Uma estrutura, em C, serve basicamente para agrupar diversas variáveis dentro de um único contexto. No nosso exemplo, podemos definir uma estrutura ponto que contenha as duas variáveis. A sintaxe para a definição de uma estrutura é mostrada abaixo:
  • 24. Estruturas
de
Dados
Compostas
 
 M" 24 Professora Aida Meira Desta forma, a estrutura ponto passa a ser um tipo e podemos então declarar variáveis deste tipo. 
 struct ponto p; Esta linha de código declara p como sendo uma variável do tipo struct ponto. Os elementos de uma estrutura podem ser acedidos através do operador de acesso “ponto” (.). Assim, é válido escrever: 
 Manipulamos os elementos de uma estrutura da mesma forma que variáveis simples. Podemos aceder seus valores, atribuir-lhes novos valores, aceder seus endereços, etc. 
 Exemplo:
Capturar e imprimir as coordenadas de um ponto.
 
 Para exemplificar o uso de estruturas em programas, vamos considerar um exemplo simples em que capturamos e imprimimos as coordenadas de um ponto qualquer. 

  • 25. Estruturas
de
Dados
Compostas
 
 M" 25 Professora Aida Meira A variável p, definida dentro de main, é uma variável local como outra qualquer. Quando a declaração é encontrada, aloca-se, na pilha de execução, um espaço para seu armazenamento, isto é, um espaço suficiente para armazenar todos os campos da estrutura (no caso, dois números reais). Atenção que o acesso ao endereço de um campo da estrutura é feito da mesma forma que com variáveis simples: basta escrever &(p.x), ou simplesmente &p.x, pois o operador de acesso ao campo da estrutura tem precedência sobre o operador “endereço de”. 
 PONTEIRO
PARA
ESTRUTURAS
 Da mesma forma que podemos declarar variáveis do tipo estrutura: struct ponto p; Podemos também declarar variáveis do tipo ponteiro para estrutura: struct ponto *pp; Se a variável pp armazenar o endereço de uma estrutura, podemos aceder os campos dessa estrutura indiretamente, através de seu ponteiro: (*pp).x = 12.0; Neste caso, os parênteses são indispensáveis, pois o operador “conteúdo de” tem precedência menor que o operador de acesso. O acesso de campos de estruturas é tão comum em programas C que a linguagem oferece outro
  • 26. Estruturas
de
Dados
Compostas
 
 M" 26 Professora Aida Meira operador de acesso, que permite aceder campos a partir do ponteiro da estrutura. Este operador é composto por um traço seguido de um sinal de maior, formando uma seta (->). Portanto, podemos reescrever a atribuição anterior fazendo: pp->x = 12.0; Em resumo, se temos uma variável estrutura e queremos aceder seus campos, usamos o operador de acesso ponto (p.x); se temos uma variável ponteiro para estrutura, usamos o operador de acesso seta (pp->x). Seguindo o raciocínio, se temos o ponteiro e queremos aceder o endereço de um campo, fazemos &pp->x 
 PASSAGEM
DE
ESTRUTURAS
PARA
FUNÇÕES
 Para exemplificar a passagem de variáveis do tipo estrutura para funções, podemos reescrever o programa simples, mostrado anteriormente, que captura e imprime as coordenadas de um ponto qualquer. Inicialmente, podemos pensar em escrever uma função que imprima as coordenadas do ponto. Esta função poderia ser dada por: void imprime (struct ponto p) { printf("O ponto fornecido foi: (%.2f,%.2f)n", p.x, p.y); } A passagem de estruturas para funções processa-se de forma análoga à passagem de variáveis simples, porém exige uma análise mais detalhada. Da forma como está escrita no código acima, a função recebe uma estrutura inteira como parâmetro. Portanto, faz-se uma cópia de toda a estrutura e a função acede aos dados desta cópia.
  • 27. Estruturas
de
Dados
Compostas
 
 M" 27 Professora Aida Meira Existem dois pontos a serem ressaltados. Primeiro, como em toda passagem por valor, a função não tem como alterar os valores dos elementos da estrutura original (na função imprime isso realmente não é necessário, mas seria numa função de leitura). O segundo ponto diz respeito à eficiência, visto que copiar uma estrutura inteira pode ser uma operação custosa (principalmente se a estrutura for muito grande). É mais conveniente passar apenas o ponteiro da estrutura, mesmo que não seja necessário alterar os valores dos elementos dentro da função. Desta forma, uma segunda (e mais adequada) alternativa para escrevermos a função imprime é: 
 void imprime (struct ponto* pp) { printf("O ponto fornecido foi: (%.2f,%.2f)n", pp->x, pp->y); } Podemos ainda pensar numa função para ler a hora do evento. Observamos que, neste caso, obrigatoriamente devemos passar o ponteiro da estrutura, caso contrário não seria possível passar ao programa principal os dados lidos: void captura (struct ponto* pp) { printf("Digite as coordenadas do ponto(x y): "); scanf("%f %f", &p->x, &p->y); } Com estas funções, nossa função main ficaria como mostrado abaixo. int main (void) { struct ponto p; captura(&p); imprime(&p);
  • 28. Estruturas
de
Dados
Compostas
 
 M" 28 Professora Aida Meira return 0; } Exercício:
 Função para determinar a distância entre dois pontos. Considere a implementação de uma função que tenha como valor de retorno a distância entre dois pontos. O protótipo da função pode ser dado por: 
 DEFINIÇÃO
DE
“NOVOS”
TIPOS
 A linguagem C permite criar nomes de tipos. Por exemplo, se escrevermos: typedef float Real; 
 Podemos usar o nome Real como um mnemônico para o tipo float. O uso de typedef é muito útil para abreviarmos nomes de tipos e para tratarmos tipos complexos. Alguns exemplos válidos de typedef: 
 typedef unsigned char UChar; typedef int* PInt; typedef float Vetor[4]; Neste fragmento de código, definimos UChar como sendo o tipo char sem sinal, PInt como um tipo ponteiro para int, e Vetor como um tipo que representa um vetor de quatro elementos. A partir dessas definições, podemos declarar variáveis usando estes mnemônicos: 
 Vetor v;
  • 29. Estruturas
de
Dados
Compostas
 
 M" 29 Professora Aida Meira ... v[0] = 3; ... Em geral, definimos nomes de tipos para as estruturas com as quais nossos programas trabalham. Por exemplo, podemos escrever: 
 struct ponto { float x; float y; }; typedef struct ponto Ponto; Neste caso, Ponto passa a representar nossa estrutura de ponto. Também podemos definir um nome para o tipo ponteiro para a estrutura. typedef struct ponto *PPonto; Podemos ainda definir mais de um nome num mesmo typedef. Os dois typedef anteriores poderiam ser escritos por: typedef struct ponto Ponto, *PPonto; A sintaxe de um typedef pode parecer confusa, mas é equivalente à da declaração de variáveis. Por exemplo, na definição abaixo: typedef float Vector[4]; Se omitíssemos a palavra typedef, estaríamos a declarar a variável Vector como sendo um vetor de 4 elementos do tipo float. Com typedef, estamos a definir um nome que representa o tipo vetor de 4 elementos float. De maneira análoga, na definição:
  • 30. Estruturas
de
Dados
Compostas
 
 M" 30 Professora Aida Meira typedef struct ponto Ponto, *PPonto; Se omitíssemos a palavra typedef, estaríamos a declarar a variável Ponto como sendo do tipo struct ponto e a variável PPonto como sendo do tipo ponteiro para struct ponto. Por fim, salienta-se que podemos definir a estrutura e associar mnemônicos para elas em um mesmo comando: typedef struct ponto { float x; float y; } Ponto, *PPonto; É comum os programadores de C usarem nomes com as primeiras letras maiúsculas na definição de tipos. Isso não é uma obrigatoriedade, apenas um estilo de codificação. VETORES
DE
ESTRUTURAS
 Já discutimos o uso de vetores para agrupar elementos dos tipos básicos (vetores de inteiros, por exemplo). Nesta seção, vamos discutir o uso de vetores de estruturas, isto é, vetores cujos elementos são estruturas. Para ilustrar a discussão, vamos considerar o cálculo da área de um polígono plano qualquer delimitado por uma sequência de n
pontos. A área desse polígono pode ser calculada somando-se as áreas dos trapézios formados pelos lados do polígono e o eixo x, conforme ilustra a Figura 

  • 31. Estruturas
de
Dados
Compostas
 
 M" 31 Professora Aida Meira FIGURA: Cálculo da área de um polígono Na figura, ressaltamos a área do trapézio definido pela aresta que vai do ponto pi ao ponto pi+1. A área desse trapézio é dada por: ( )( ) / 2 i 1 i i 1 i a # x ! x y " y " " . Somando-se as “áreas” (algumas delas negativas) dos trapézios definidos por todas as arestas chega-se a área do polígono (as áreas externas ao polígono são anuladas). Se a sequência de pontos que define o polígono for dada em sentido anti-horário, chega-se a uma “área” de valor negativo. Neste caso, a área do polígono é o valor absoluto do resultado da soma. Um vetor de estruturas pode ser usado para definir um polígono. O polígono passa a ser representado por uma sequência de pontos. Podemos, então, escrever uma função para calcular a área de um polígono, dados o número de pontos e o vetor de pontos que o representa. Uma implementação dessa função é mostrada abaixo. Um exemplo de uso dessa função é mostrado no código abaixo:
  • 32. Estruturas
de
Dados
Compostas
 
 M" 32 Professora Aida Meira int main (void){ Ponto p[3] = {{1.0,1.0},{5.0,1.0},{4.0,3.0}}; printf("area = %fn",area (3,p)); return 0; } Exercício:
 Altere o programa acima para capturar do teclado o número de pontos que delimitam o polígono. O programa deve, então, alocar dinamicamente o vetor de pontos, capturar as coordenadas dos pontos e, chamando a função área, exibir o valor da área. 
 VETORES
DE
PONTEIROS
PARA
ESTRUTURAS
 Da mesma forma que podemos declarar vetores de estruturas, podemos também declarar vetores de ponteiros para estruturas. O uso de vetores de ponteiros é útil quando temos que tratar um conjunto elementos complexos. Para ilustrar o uso de estruturas complexas, consideremos um exemplo em que desejamos armazenar uma tabela com dados de alunos. Podemos organizar os dados dos alunos em um vetor. Para cada aluno, vamos supor que sejam necessárias as seguintes informações: • nome:
cadeia
com
até
80
caracteres
 • matricula:
número
inteiro
 • endereço:
cadeia
com
até
120
caracteres
 • telefone:
cadeia
com
até
20
caracteres Para estruturar esses dados, podemos definir um tipo que representa os dados de um aluno: struct aluno { char nome[81];
  • 33. Estruturas
de
Dados
Compostas
 
 M" 33 Professora Aida Meira int mat; char end[121]; char tel[21]; }; typedef struct aluno Aluno; Vamos montar a tabela de alunos usando um vetor global com um número máximo de alunos. Uma primeira opção é declarar um vetor de estruturas: #define MAX 100 Aluno tab[MAX]; Desta forma, podemos armazenar nos elementos do vetor os dados dos alunos que queremos organizar. Seria válido, por exemplo, uma atribuição do tipo: ... tab[i].mat = 9912222; ... No entanto, o uso de vetores de estruturas tem, neste caso, uma grande desvantagem. O tipo Aluno definido acima ocupa pelo menos 227 (=81+4+121+21) bytes1. A declaração de um vetor desta estrutura representa um desperdício significativo de memória, pois provavelmente estamos a armazenar um número de alunos bem inferior ao máximo estimado. Para contornar este problema, podemos trabalhar com um vetor de ponteiros. typedef struct aluno *PAluno; #define MAX 100 PAluno tab[MAX]; Assim, cada elemento do vetor ocupa apenas o espaço necessário para armazenar um ponteiro. Quando precisarmos alocar os dados de um aluno
  • 34. Estruturas
de
Dados
Compostas
 
 M" 34 Professora Aida Meira numa determinada posição do vetor, alocamos dinamicamente a estrutura Aluno e guardamos seu endereço no vetor de ponteiros. Considerando o vetor de ponteiros declarado acima como uma variável global, podemos ilustrar a implementação de algumas funcionalidades para manipular nossa tabela de alunos. Inicialmente, vamos considerar uma função de inicialização. Uma posição do vetor estará vazia, isto é, disponível para armazenar informações de um novo aluno, se o valor do seu elemento for o ponteiro nulo. Portanto, numa função de inicialização, podemos atribuir NULL a todos os elementos da tabela, significando que temos, a princípio, uma tabela vazia. void inicializa (void) { int i; for (i=0; i<MAX; i++) tab[i] = NULL; } Uma segunda funcionalidade que podemos prever armazena os dados de um novo aluno numa posição do vetor. Vamos considerar que os dados serão fornecidos via teclado e que uma posição onde os dados serão armazenados será passada para a função. Se a posição da tabela estiver vazia, devemos alocar uma nova estrutura; caso contrário, atualizamos a estrutura já apontada pelo ponteiro. void preenche (int i) { if (tab[i]==NULL) tab[i] = (PAluno)malloc(sizeof(Aluno)); printf("Entre com o nome:"); scanf(" %80[^n]", tab[i]->nome);
  • 35. Estruturas
de
Dados
Compostas
 
 M" 35 Professora Aida Meira printf("Entre com a matricula:"); scanf("%d", &tab[i]->mat); printf("Entre com o endereco:"); scanf(" %120[^n]", tab[i]->end); printf("Entre com o telefone:"); scanf(" %20[^n]", tab[i]->tel); Podemos também prever uma função para remover os dados de um aluno da tabela. Vamos considerar que a posição da tabela a ser liberada será passada para a função: void remove (int i) { if (tab[i] != NULL) { free(tab[i]); tab[i] = NULL; } } Para consultarmos os dados, vamos considerar uma função que imprime os dados armazenados numa determinada posição do vetor: void imprime (int i) { if (tab[i] != NULL) { printf("Nome: %sn”, tab[i]->nome); printf("Matrícula: %dn”, tab[i]->mat); printf("Endereço: %sn”, tab[i]->end); printf("Telefone: %sn”, tab[i]->tel); } }
  • 36. Estruturas
de
Dados
Compostas
 
 M" 36 Professora Aida Meira Por fim, podemos implementar uma função que imprima os dados de todos os alunos da tabela: void imprime_tudo (void) { int i; for (i=0; i<MAX; i++) imprime(i); } Exercício:
 Faça um programa que utilize as funções da tabela de alunos escritas acima. Exercício:
 Re-escreva as funções acima sem usar uma variável global. Sugestão: Crie um tipo Tabela e faça as funções receberem este tipo como primeiro parâmetro.