Escolar Documentos
Profissional Documentos
Cultura Documentos
Módulo 7 ‐ Conceito de Estruturas dinâmicas.
As variáveis em Pascal são criadas na memória. São definidas no programa principal (código) e quando se
executa o programa elas vão ocupar o seu espaço no segmento de dados da memória RAM. O que podemos
concluir é que o espaço ocupado pelos dados em memória não aumenta ao longo da execução do programa.
Exemplo:
Se definirmos uma estrutura tipo array
Var nomes:array[1..5] of string;
Esta estrutura de dados irá ocupar 256x5 bytes em memória visto que cada string ocupa 256 bytes. Se na
altura da execução do programa pretendermos aumentar o nº de strings não podemos.
Podemos resolver este problema utilizando estruturas dinâmicas de memória, em que não definimos um
tamanho específico para a estrutura mas vamos pedindo memória ao Sistema Operativo de acordo com as
necessidades. Obviamente não vamos trabalhar com as variáveis do tipo array, mas sim utilizando ponteiros
que são variáveis que identificam zonas de memória que pedimos ao S.O. (Sistema Operativo). Portanto no
programa principal vamos definir alguns ponteiros ou um ponteiro para uma estrutura de dados tipo registo
(record) e no programa em execução cada vez que precisamos de mais memória pede‐se ao S. O. Essa
memória e guarda‐se o endereço de memória num ponteiro.
O Ponteiro passa a ser o equivalente a um espécie de “pega” para a zona de dados em memória, assim como
uma variável tem o seu nome que também é uma “pega” para uma zona de dados, só que trabalham de
maneira distinta os ponteiros trabalham com memória dinâmica e as variáveis são memórias estáticas, isto é,
Memória Estática são as variáveis que estão definidas durante o programa inteiro estão na zona de
dados do programa, não aumentam nem diminuem. Olimite de utilização desta memória são 64Kbytes que é
o tamanho do segmento de dados.
Memória Dinâmica, são zonas de dados que ao longo da execução do programa são pedidas ao Sistema
Operativo e cujo endereço armazenamos em ponteiros. A memória dinâmica tem como limite de utilização a
capacidade de memória do computador que pode ascender a 1Gbyte ou mais.
Declaração de Ponteiros.
Um ponteiro é uma variável que vai conter um endereço de uma zona de memória que corresponde a um
tipo de dado concreto. Por exemplo podemos definir um ponteiro para um byte:
Var ptr_byte:^byte;
Esta variável poderá conter um endereço de memória de uma zona de dados do tipo BYTE, caso contrário dá
erro! Como podemos pedir memória ao S.O. e atribuir o valor 5 à essa zona?:
Var ptr_byte:^byte;
Prof. Agostinho Andrade 11º CPIG
Agrupamento Antº José de Almeida 2009/20010 pag. 1/6
Begin
Ptr_byte Ptr($62E8,$0)
Getmem(ptr_byte,sizeof(byte)); Ù
5 5
Ptr_byte^:=5;
Freemem(ptr_byte, sizeof(byte));
End.
Deste exemplo podemos retirar várias informações: O ptr_byte vai conter o valor ($62E8,$0) que é um
endereço de memória que contém por sua vez o valor “5”, tal como foi dito o ponteiro é uma espécie de
“etiqueta” ou “pega” para a zona de dados. Nota importante: Quando um ponteiro não aponta para
nenhuma zona de memória ele deve conter o valor NIL, isto é a indicação de que não está a apontar para
nenhum endereço de memória (isto é não contém nenhum endereço de memória).
Uma outra situação que pode ser necessária é nós obtermos o endereço de uma variável e coloca‐la num
ponteiro, para isso usamos as instrução @, que vai dar o endereço de memória onde está colocada a dita
variável.
Var Aluno:byte
Ptr_aluno:^byte;
Begin
Aluno Ptr($62E8,$0)
Aluno:=5; Ù
5 5
Ptr_aluno:=@aluno;
Writeln(Ptr_aluno^); (* vai escrever no monitor o conteúdo da célula para onde o ptr_aluno está
a apontar, que neste caso é a variável aluno, logo aparece o 5 *)
End.
Qual a vantagem deste tipo de utilização da memória?
A vantagem é a quantidade de informação que podemos colocar em memória e a independência que essa
quantidade tem na execução do programa, isto é, numa dada altura ao executar o programa poderei precisar
de 500Kbyte de memória mas noutra poderei precisar de 4Mbyte.
Como podemos armazenar esta informação?
Podemos armazenar em listas de dados interligados:
Prof. Agostinho Andrade 11º CPIG
Agrupamento Antº José de Almeida 2009/20010 pag. 2/6
Os dados são colocados em memória mas há um elemento de ligação que permite percorrer a lista do
princípio ao fim.
Quantos tipos de lista existem?
Basicamente há dois tipo
• A “pilha” ou “stack” em inglês, que também é chamada de LIFO (Last in first out, tradução: último a
entrar primeiro a sair)
O primeiro elemento a entrar foi o “A” e o
último foi o “D”, mas o primeiro a sair será
o “D” e o último será o “A”
• O “fila circular” ou “buffer” em inglês, que também é chamada de FIFO (First in first out, tradução:
primeiro a entrar primeiro a sair)
entra D C B A sai
O primeiro a entrar foi o “A” e vai ser o primeiro a sair
Como podemos então armazenar dados e fazer as ligações entre eles?
Vamos necessariamente usar registos (records) para criar um TYPE em Pascal que possa armazenar
os dados que entendemos e os ponteiros para fazer a ligação:
type
ptrTficha=^tficha;
tficha=record
ptr_seguinte:ptrTficha;
numero:byte;
end;
var ptr_ficha:ptrTficha;
Prof. Agostinho Andrade 11º CPIG
Agrupamento Antº José de Almeida 2009/20010 pag. 3/6
Neste exemplo temos a definição de um TYPE ponteiro para um record que vai conter por sua vez
um ponteiro para este novo type que definimos (isto para fazer a ligação entre elementos da lista) e
a zona de dados que neste caso é um byte. Como podemos ver só vamos fazer a ligação para o
próximo elemento da lista, isto quer dizer que não podemos andar para trás, só para a frente
portanto estamos perante um lista unidireccional.
Depois de definirmos um type, vamos declarar uma variável ponteiro para esse type, essa variável é
quanto basta para começarmos a fazer a nossa lista, pois o seguinte elemento será endereço de
memória que estiver na ligação do próximo (ptr_seguinte) e assim sucessivamente até que o
ptr_seguinte=NIL, situação que marca o fim da lista.
Ver os programas executados nas aulas sobre a ligação e utilização das listas unidirecionais.
Quantos tipos de listas existem?
Há dois tipos de listas:
• a unidireccional onde apenas temos um ponteiro de ligação e apenas percorremos a lista num só
sentido. Normalmente devemos sempre guardar o endereço da extremidade por exemplo o início:
ex:
type
ptrTficha=^tficha;
tficha=record
ptr_seguinte:ptrTficha;
numero:byte;
end;
var ptr_ficha, ptr_inicio, ptr_actual:ptrTficha;
opcao:char;
num:byte;
begin
ptr_inicio:=NIL;
repeat
writeln(‘Introduza um valor’);
readln(num);
if ptr_inicio=NIL then
begin
getmem(ptr_ficha,sizeof(tficha)); {pedido de memória ao S. O.}
{depois de pedir memória, vamos edita‐la com os valores que queremos}
ptr_ficha^. ptr_seguinte:=NIL; {não há próximo elemento}
ptr_ficha^. numero:=num; {coloca‐se o valor na zona de memória}
ptr_inicio:=ptr_ficha; {vamos copiar o enderço para o ptr_inicio pois se trata da 1ª
ficha que estamos a inserir na lista}
end
Prof. Agostinho Andrade 11º CPIG
Agrupamento Antº José de Almeida 2009/20010 pag. 4/6
else
begin
getmem(ptr_ficha,sizeof(tficha)); {pedido de memória ao S. O.}
{depois de pedir memória, vamos edita‐la com os valores que queremos}
ptr_ficha^. ptr_seguinte:=NIL; {não há próximo elemento}
ptr_ficha^. numero:=num; {coloca‐se o valor na zona de memória}
{agora vamos procurar o local onde colocar esta nova ficha que já está pronta, devemos procurar o fim da lista e
coloca‐la a seguir}
ptr_actual:=ptr_inicio {começa a partir do início da lista}
while ptr_actua^.ptr_seguinte<>Nil do
ptr_actual:= ptr_actua^.ptr_seguinte; { vai fazer um ciclo que em ptr_actual vai estar a entrar sempre a
próxima ficha até que chega ao fim da lista e para}
{ como estamos com ptr_actual no último elemento da lista podemos actualiza‐lo para acrescentar outro elemento à
lista}
ptr_actua^.ptr_seguinte:=ptr_ficha; {já está, o ptr_actual já tem próximo}
end;
writeln(‘quer sair?’);
readln(opcao);
until opcao=’s’;
{ como não precisamos mais da memória, vamos liberta‐la. Para isso temos que percorrer todos os elementos da lista e ir
libertando um a um}
ptr_actual:=ptr_inicio {começa a partir do início da lista}
while ptr_actua^.ptr_seguinte<>Nil do
begin
ptr_ficha:=ptr_actual; { guarda o actual em ptr_ficha para poder liberta‐lo, isto é, vamos eliminar todos os
elementos começando no início da lista e indo até ao fim, nas aulas fizemos ao contrário!}
ptr_actual:= ptr_actua^.ptr_seguinte; { prepara já o próximo endereço}
freemem(ptr_ficha,sizeof(tficha)); {liberta o endereço que está em ptr_ficha pois já temos o endereço do
próximo em ptr_actual}
end;
freemem(ptr_actual,sizeof(tficha)); {como já não há mais nenhum element já não se entrou o ciclo While logo
ficou apenas o elemento que estava em ptr_actual, portanto há que liberta‐lo e acabou o programa}
end.
Atenção que este exemplo nos mostra que quando pedimos memória ao S. O. Temos que liberta‐
la porque senão vamos consumindo a memória do S.O. até que o sistema pare por completo.
• No outro tipo de lista temos as listas duplamente ligadas ou bidireccionais. Estas listas são mais
práticas visto que podemos percorre‐las nos dois sentidos.
type
ptrTficha=^tficha;
tficha=record
ptr_seguinte:ptrTficha;
ptr_anterior:ptrTficha;
numero:byte;
end;
Prof. Agostinho Andrade 11º CPIG
Agrupamento Antº José de Almeida 2009/20010 pag. 5/6
var ptr_ficha:ptrTficha;
Com estes exemplos podemos fazer armazenamento de dados em memória dinamicamente de
quantos elementos nós desejarmos com total independência do programa principal pois só depende
do momento de execução.
Ver programas das aulas.
Prof. Agostinho Andrade 11º CPIG
Agrupamento Antº José de Almeida 2009/20010 pag. 6/6