Ŀ
X - Variveis dinmicas


X.1 - Comparao entre variveis estticas e variveis dinmicas.
      ----------------------------------------------------------

        At  o  presente momento, lidamos com variveis que tiveram de  ser
        criadas antes de se executar um programa. So variveis que existem
        o tempo todo, ou seja, so variveis estticas. Portanto,a alocao
        de memria para esse tipo de varivel  feita antes da execuo  do
        programa.  A  grande desvantagem desse tipo de varivel  o fato de
        que uma vez criada, o espao de memria que ela ocupa no pode mais
        ser  alterado.  As   variveis  dinmicas  podem  ser  criadas e ou
        destrudas  durante  a  execuo de um programa, e esta,  a grande
        vantagem delas sobre as estticas. As variveis dinmicas podem ser
        obtidas atravs de um tipo pr-definido em Pascal, chamado Pointer.

        O  pointer  ou  apontador,  como o prprio nome diz, aponta para um
        local de memria onde est armazenada uma varivel.


X.2 - O tipo Pointer
      --------------

        O   procedimento  para  se  declarar uma varivel do tipo pointer 
        simples, seno vejamos:

        Var
                p : ^Integer;

        Aps  esta declarao, teramos criado uma varivel do tipo pointer
        que  ocupa  4  bytes (lembre-se  que ela aponta um endereo, e como
        sabemos,   no  IBM/PC,  um  endereo   formado pelo Segment e pelo
        offset, cada um com 2 bytes) e que ir apontar uma varivel do tipo
        Integer. Eu utilizei como exemplo, o tipo Integer, mas poderia  ser
        qualquer outro tipo e at mesmo Records.

        At  esse  instante,  no criamos a to famosa varivel dinmica, e
        sim uma varivel do tipo pointer, que ir apontar o endereo de uma
        varivel  dinmica  do  tipo Integer. Isto parece meio complicado a
        princpio, mas  aos  poucos,  iremos entender o funcionamento desse
        novo tipo de varivel.

        E  agora  eu  pergunto,  para onde est apontando a varivel recm-
        criada chamada p ? Simplesmente para nenhum lugar. E isto recebe  o
        nome em Pascal de NIL. Quando escrevemos no meio de  um  programa a
        declarao abaixo:

        p := NIL;

        Estamos  querendo  dizer que a varivel do tipo pointer, chamada p,
        no  est  apontando  para  nenhuma varivel no momento. Sempre que
        criamos uma varivel do tipo pointer, ela tem o valor inicial NIL.


X.3 - Criao de variveis dinmicas.
      ------------------------------

        O prximo passo,  a criao de uma varivel dinmica, para  tanto,
        utilizamos a procedure New. Sua sintaxe :

        New(p);

        Isto faz com que seja alocado um espao de memria, suficiente para
        armazenar uma varivel do tipo associado a p, no caso integer. Esse
        espao de memria fica num local especial chamado HEAP. No  caso do
        IBM/PC,  o  HEAP   toda  a  memria  no utilizada pelo sistema.

        Portanto,  a  declarao New(p) aloca um espao de memria no HEAP,
        suficiente  para armazenar uma varivel do tipo Integer e retorna o
        endereo inicial desta regio de memria para a varivel p. Lembre-
        se que p  do tipo pointer.

        A  grande  questo agora : Como acessamos essa varivel dinmica?.
        Atravs da seguinte simbologia:

        p^

        Est na hora de um exemplo para esclarecer melhor as coisas:

        ---------------------------------------------------------
        Program Exemplo;
        Uses CRT;

        Type  Ponteiro = ^Integer;

        Var p : Ponteiro;
            i : Integer;

        (* p  uma varivel do tipo pointer que aponta para variveis
           dinmicas do tipo integer *)

        Begin
           ClrScr;
           If p = NIL Then Writeln('sim');

        (* como p acabou de ser criada, ela no deve estar apontando para
           algum endereo, ou seja, seu valor inicial deve ser NIL. Para
           descobrirmos se isso  verdadeiro, basta compar-la com NIL *)

           New(p);

        (* acabamos de criar uma varivel dinmica do tipo Integer, e
           seu endereo foi colocado no pointer p *)

           p^:=100;

        (* estamos atribuindo o valor 100  varivel dinmica recm-
           criada *)

           Writeln(p^);

           i:=200;
           p^:=i;
           Writeln(p^);  (* ser escrito 200 *)

        (* A funo addr(var) retorna o endereo da varivel var *)

           p:=addr(i); (* o pointer contm agora o endereo da
                          varivel i *)

           p^:=1000;   (* indiretamente estou atribuindo o valor
                          1000  varivel i *)

           Writeln(i); (* ser escrito 1000 *)
        End.
        ---------------------------------------------------------


X.4 - Estruturas de dados com ponteiros
      ---------------------------------

        Suponha  que  voc tenha que fazer um programa que ter que ler uma
        certa quantidade indeterminada de registros  do teclado.  Voc  no
        sabe  se  sero  10,  100  ou at 1000 registros. A princpio, voc
        poderia super-dimensionar um array, desde que seu computador  tenha
        memria suficiente, mas mesmo assim,corre-se o risco de ,no futuro,
        termos que redimensionar a matriz. Para um caso como este,  podemos
        utilizar o conceito de  variveis  dinmicas.  Para  tanto, devemos
        declarar  um pointer para uma varivel, cuja estrutura seja consti-
        tuda de dois campos: um contendo o valor propriamente dito que  se
        quer armazenar e o outro apontando para a prxima varivel dinmica.

        Exemplo:
        ---------------------------------------------------------
        Program Exemplo;
        Uses CRT;

        (********************************************************
         Este programa l registros com a estrutura abaixo, at
         que se digite 'fim' quando  perguntado o nome da
         pessoa. Repare que o programa tem a capacidade de ler um
         nmero ilimitado de registros sem a preocupao de se
         definir um array e sua respectiva dimenso.

         Nome  : String[30];

         Sexo  : Char;

         Idade : Integer;

         Altura: Real;

        ********************************************************)

        Type

             Pessoa   = Record
                              Nome  : String[30];
                              Sexo  : Char;
                              Idade : Integer;
                              Altura: Real;
                        End;

             ponteiro = ^Pessoas;

             Pessoas  = Record
                              Valor : Pessoa;
                              Prox  : Ponteiro;
                        End;

        Var
             p,prim : Ponteiro;

        Procedure Linha;
        Var i:integer;
        Begin
           For i:=1 to 80 do write('-')
        End;

        Begin
           Prim:=nil;
           ClrScr;
           Repeat
              Linha;
              New(p);
              Write('Nome da pessoa -----> ');
              Readln(p^.valor.Nome);
              If (p^.valor.Nome<>'fim')
              Then Begin
                      Write('Sexo ---------------> ');
                      Readln(p^.valor.Sexo);
                      Write('Idade --------------> ');
                      Readln(p^.valor.Idade);
                      Write('Altura -------------> ');
                      Readln(p^.valor.altura);
                      p^.Prox:=Prim;
                      Prim:=p;
                   End;
           Until p^.valor.nome='fim';

           ClrScr;
           Linha;
           p:=prim;
           While p<>nil do
           Begin
              With p^.valor do
                 Writeln(nome:30,sexo:5,idade:5,altura:6:2);
              p:=p^.prox;
           End;

        End.
        ---------------------------------------------------------


X.5 - Procedures para variveis dinmicas
      -----------------------------------

X.5.1 - Dispose

        Esta procedure libera o espao ocupado pela varivel em questo que
        deve ser do tipo pointer.Ela no mexe com o resto do HEAP. Sintaxe:

        Dispose(Var);

        Podemos dizer que Dispose  contrrio a New, pois esta aloca espao
        no HEAP para determinado tipo de varivel enquanto  Dispose  libera
        este espao.


X.5.2 - Mark e Release

        Como  vimos,  as  variveis  dinmicas so armazenadas num local de
        memria  especial  chamado de HEAP. Esse trecho de memria funciona
        como  se fosse uma pilha. E para controlar o topo da pilha, o Turbo
        Pascal   mantm   um  apontador.   Ns  podemos  alterar o valor do
        apontador do topo do HEAP. No podemos esquecer que  alterarando  o
        valor deste apontador, todas as variveis dinmicas  que  estiverem
        acima deste endereo sero perdidas. A procedure  que  nos  permite
        alterar o valor deste apontador  a Release e sua sintaxe :

        Release(Var);

        Onde Var deve ser uma varivel do tipo pointer e  que deve conter o
        endereo desejado, para se atribuir ao apontador do topo do HEAP.

        J a procedure Mark nos permitem atribuir, a uma varivel  do  tipo
        pointer, o valor atual do apontador do topo do HEAP. Sintaxe:

        Mark(Var);

        Estas duas procedures em conjunto nos permite controlar  e  liberar,
        quando desejarmos, um trecho de memria do HEAP.


X.5.3 - GetMem e FreeMem

        Com   a  procedure  New,  podemos alocar espao necessrio no  HEAP
        somente  para  uma  varivel  de determinado tipo. Com o par Mark e
        Release  ou  Dispose,  podemos  liberar  tal espao no HEAP. J, as
        procedures GetMem e FreeMem, podemos alocar o nmero de  bytes  que
        desejarmos, sem estarmos  presos a um determinado tipo de varivel.
        Sintaxes:

        GetMem(Var,i);

        Onde Var  do tipo pointer e i Integer.

        Aps esta declarao, teramos alocado no HEAP,um espao de memria
        no HEAP no tamanho de i bytes. O endereo  inicial  desse trecho de
        memria  retornado em Var.

        FreeMem(Var,i);

        Esta procedure faz exatamente o contrrio da GetMem, ou seja,libera
        i bytes no HEAP a partir do endereo armazenado em Var.


X.6 - Functions para variveis dinmicas
      ----------------------------------

X.6.1 - MaxAvail

        Retorna  um nmero inteiro, que corresponde ao nmero de pargrafos
        (conjunto de 16 bytes) livres disponveis no maior bloco de  espao
        contguo no HEAP.


X.6.2 - MemAvail

        Retorna o nmero de pargrafos disponveis no HEAP.


