Ponteiros no Pascal / Delphi - Alocando memória dinamicamente

Nos últimos artigos sobre ponteiros, foi explicado o que é e o como fazer para o ponteiro apontar para um variável existente, neste irei explicar como usar o ponteiro para apontar para um endereço de memória alocado dinamicamente.

Vimos que para um ponteiro apontar para uma variável, bastava lermos o endereço de memória da variável usando o operador @ e atribuír-lo ao ponteiro:

p := @i;

E caso quisessemos escrever onde o ponteiro estava apontando usamos o operador de dereferência ^:

p^ := 1;

Além dos ponteiros apontarem para endereços de memória já existentes, eles também podem ser usados para apontar para endereços de memória que são alocados. No Pascal / Delphi para alocar um bloco de memória temos o procedimento GetMem:

procedure GetMem(var P: Pointer; Size: Integer);

No primeiro parâmetro passamos uma variável do tipo ponteiro e no segundo o tamanho em byte que queremos alocar. Para sabermos o tamanho da memória que queremos alocar podemos usar a função SizeOf:

function SizeOf(X): Integer;

X pode ser uma variável ou um tipo, esta função retorna o número de bytes que aquela variável ou tipo precisam.

Quando não precisarmos mais deste bloco de memória alocado, podemos utilizar o procedimento FreeMem:

procedure FreeMem(var P: Pointer[; Size: Integer]);

Ele faz o oposto do GetMem, desalocando o bloco de memória apontado pelo ponteiro passado no primeiro parâmetro.

Exemplo de alocação dinâmica:

program Project2;
{$APPTYPE CONSOLE}

uses SysUtils;

type
  PInteger = ^Integer;
var
  p: PInteger;
begin
  GetMem(p, SizeOf(Integer));
  try
    p^ := 2;
    WriteLn(Format(‘%d’, [p^]));
  finally
    FreeMem(p, SizeOf(Integer));
  end;
  ReadLn;
end.

Inicialmente declaramos p como um ponteiro que apontará para um Integer, depois alocamos um espaço em memória de tamanho SizeOf(Integer)  bytes (nos compiladores atuais de 32 bits, um Integer ocupa 32 bits ou 4 bytes). A partir deste momento em p é retornado este endereço alocado.

A instrução p^ := 2; faz atribuir o valor 2 como se fosse um Integer na região de memória alocada, na instrução seguinte é mostrado o conteúdo da memória como se fosse um Integer na tela.

Finalizando temos a desalocação da memória. Isso diz para o sistema operacional que a memória pode ser alocada para outra função. Veja que colocamos o código dentro de um bloco try..finally..end; para garantir que se alguma excessão ocorrer durante a utilização do bloco de memória alocado, esta memória seja desalocada. Assim evitando o aparecimento de uma vazamento de memória (memory leak). O segundo parâmetro do procedimento FreeMem é opcional, coloquei no nosso exemplo apenas para entendermos o processo, internamente quando se usa o GetMem, é guardado o tamanho do espaço alocado, assim quando se chama o FreeMem para um determinado endereço, o FreeMem já saberá o quanto de memória é necessário desalocar.

O GetMem e o FreeMem são os equivalentes ao malloc e free da linguagem C. Em Pascal / Delphi, contamos ainda com um par de procedimentos:

procedure New(var P: Pointer);

procedure Dispose(var P: Pointer);

O New e o Dispose alocam o tamanho de memória que o ponteiro P aponta. Assim não precisamos especificar o tamanho em bytes a ser alocado. O nosso exemplo anterior pode ser reescrito:

program Project2;
{$APPTYPE CONSOLE}

uses SysUtils;

type
  PInteger = ^Integer;
var
  p: PInteger;
begin
  New(p);
  try
    p^ := 2;
    WriteLn(Format(‘%d’, [p^]));
  finally
    Dispose(p);
  end;
  ReadLn;
end.

Atenção, após o FreeMem ou Dispose, p continua apontando para o mesmo endereço, só que este não está mais lá. Perceba que existe um risco em se usar um ponteiro, que é justamente apontar para algo que não deveria estar apontando. Uma boa prática é atribuir nil para o ponteiro que foi desalocado. Assim se por engano o ponteiro for utilizado, uma excessão do tipo EAccessViolation será lançada, detectando o problema, antes que seja tarde :-)

 finally
    Dispose(p);
    p := nil;
  end;

0 Respostas para “Ponteiros no Pascal / Delphi - Alocando memória dinamicamente”


  1. Sem comentários

Deixe uma Resposta