Apontadores (Ponteiros)
Um apontador é uma variável que contém o endereço de um dado ou de um código de programa. Podemos obter o endereço de uma variável usando a função Addr ou o operador @.
var N :
integer;
begin
writeln('Addr(N)=', longint(Addr(N)));
writeln('@N=', longint(@N))
end.
Variável tipo Pointer
Usa-se uma variável tipo Pointer para armazenar um endereço de memória.
var <nome-da-variável> : Pointer;
Este tipo de apontador pode ser usado para guardar o endereço de qualquer variável, independente do tipo da mesma.
var
N : integer;
R : real;
S : String[50];
P : Pointer;
begin
P := Addr(N); {1}
writeln('Addr(N)=', longint(P));
P := Addr(R); {2}
writeln('Addr(R)=', longint(P));
P := @S; {3}
writeln('Addr(S)=', longint(P));
end.
Supondo que N, R, S e P estão juntos na memória, teríamos uma organização semelhante à abaixo:
Apontadores Tipados
São apontadores que podem ser usados para referenciar um tipo específico. São declarados da seguinte forma:
var <nome-da-variável> : ^<tipo>;
type
TItem = record
Nome : String;
Preco : real;
end;
var
PItem : ^TItem;
Item : TItem;
begin
Item.Nome := 'Livro de Ed1';
Item.Preco := 25.0;
PItem := Addr(Item);
end.
Desreferenciando um Apontador
Desreferenciar um apontador faz com que obtenhamos o valor contido no endereço apontado.
<identificador>^
A atribuição de apontadores é igual a uma variável normal.
var
X : integer;
P1, P2 : ^integer;
begin
X := 10;
P1 := @X;
writeln(X);
writeln(P1^);
P2 := P1;
P2^ := 100;
writeln(X)
end.
A Constante Nil
É uma constante que representa um endereço de memória inválido, ou seja, um apontador com esse valor não aponta para nada.
Variáveis Dinâmicas
São variáveis que são criadas e destruídas durante a execução do programa (dinamicamente e sob demanda). Não são associados a um identificador. Não são declaradas na seção de declaração de variáveis. São sempre referenciadas através de apontadores.
Permitem melhor gerenciamento da memória, já que podem ser alocadas sob demanda e liberadas assim que não forem mais necessárias.
Suportam a criação de estruturas de dados complexas de forma eficiente, como listas encadeadas e árvores.
Em certas situações, são mais eficientes do que estruturas estáticas, permitindo que o programador decida qual é melhor em cada situação.
Porém, o uso de variáveis dinâmicas está associada a mais erros de programação, já que a alocação e desalocação de memória fica a cargo do programador.
Alocação e Desalocação de Variáveis Dinâmicas
Há uma função chamada new que dado um apontador cria uma variável dinâmica do tipo do apontador e faz com que o apontador tipado passado aponte para a variável criada.
new (<apontador-tipado>)
Para liberar a memória alocada pela função new, usa-se o procedimento dispose.
dispose (<apontador-tipado>)
type
TItem = record
Nome : String[20];
Preco : real
end;
var
PItem, PAnterior : ^TItem;
begin
New(PItem);
PItem^.Nome := 'Livro de ED1';
PItem^.Preco := 30.0;
PAnterior := PItem;
New(PItem);
PItem^.Nome := 'Outro livro';
PItem^.Preco := 10.0;
writeln(PAnterior^.Nome);
writeln(PAnterior^.Preco);
writeln(PItem^.Nome);
writeln(PItem^.Preco);
Dispose(PAnterior);
Dispose(PItem);
PItem := nil;
PAnterior := nil
end.
type
PItem = ^TItem;
TItem = record
Nome : string[20];
Preco : real;
Proximo : PItem
end;
var
Head : PItem;
PNew : PItem;
Resp : char;
begin
Head := nil;
repeat
New(PNew);
writeln('Digite o nome e o preco do Item:');
readln(PNew^.Nome, PNew^.Preco);
PNew^.Proximo := Head;
Head := PNew;
write('Outro Item (S/N)?');
readln(Resp);
until UpCase(Resp) = 'N';
end.
Alocando e Desalocando Memória usando GetMem e FreeMem
GetMem(<apontador>, <número-de-bytes>)
FreeMem(<apontador>, <número-de-bytes>)
A Lista de Blocos Livres
Ao desalocar uma variável dinâmica, normalmente cria-se um espaço vazio na memória. O endereço e o tamanho desta variável são incluídos na lista de blocos livres. As funções New e GetMem verificam se há um bloco livre na lista com o tamanho desejado.
As funções MaxAvail e MemAvail
MaxAvail retorna o tamanho do maior bloco de memória livre, incluindo o bloco que começa no topo do heap.
MemAvail retorna a soma dos tamanhos de todos os blocos livres.
var
P : Pointer;
begin
writeln('MaxAvail:', MaxAvail, ', MemAvail:', MemAvail);
GetMem(P, 5000);
writeln('MaxAvail:', MaxAvail, ', MemAvail:', MemAvail);
FreeMem(P, 5000);
writeln('MaxAvail:', MaxAvail, ', MemAvail:', MemAvail);
end.
Cuidados com o Dispose
Após executar Dispose o apontador continua apontado para o mesmo endereço
Erros Comuns com Apontadores