As linguagens de programação modernas tornaram possível explicitar não apenas o acesso aos dados, mas também aos endereços desses dados.
Isso significa que ficou possível a utilização de ponteiros explicitamente. Assim, existe um distinção de notação entre um dado e a sua referência (ou endereço).
A notação introduzida por Wirth, com a introdução
de Pascal, é:
type T = meu_tipo;
. . .
Type Tp = ^TEssa declaração expressa que valores do tipo Tp são ponteiros para dados do tipo T.
Ele armazena um endereço de memória. Esse endereço deve ser a posição de início do armazenamento de um dado do tipo T.
Portanto, lemos o simbolo ^ como sendo ponteiro para... , e na declaração acima lemos 'Tp é um ponteiro para variáveis do tipo T'.
O fato de que o tipo dos elementos apontados ser evidente na declaração do ponteiro tem importância fundamental. Isso distingue ponteiros de linguagens de alto nível de endereços em Assembly.
Valores para ponteiros são gerados quando dados correspondentes a seus tipos são alocados/desalocados dinamicamente. Em Pascal, os procedimentos dispose existem com esse propósito.
Portanto, deixa-se a cargo do programa (via linguagem de programação), e não do programador, prover e devolver espaço para inserções e eliminações em tempo de execução (Veja algumas operações em lista utilizando ponteiros).
Custo: Tempo de execução comprometido.
Idéia: O programador declara apenas o tipo de registro que contém um elemento da lista, e avisa que a alocação será dinâmica. Sempre que requisitar um registro novo para a inserção, ou liberar um registro a ser eliminado, o programador lança mão de duas rotinas pré-definidas para este fim.
Type prec = ^rec; Lista = prec; rec = record info: T; {seu tipo preferido} lig: Lista; End; Var p, L: Lista; {nossos ponteiros }Um ponteiro do tipo Lista pode assumir o conjunto de valores que correspondem a endereços reais de memória. Por exemplo, sendo var p: Lista podemos ter:
onde o conteúdo de p corresponderia ao endereço do objeto. Esses endereços serão as ligações das listas encadeadas dinâmicas.
Sendo o registro:
O acesso ao registro depende do tipo da alocação. Se compararmos alocação em array com alocação dinâmica com ponteiros, temos que para acessar o conteúdo de uma variável fazemos:
alocação alocação array L.A[p] dinâmica p^Para designar ponteiro, objeto e campos, a notação utilizada é:
ponteiro: p objeto: p^ campos: p^.info p^.lig
1: L := nil; 2: If (p = nil) Then ...Ponteiro x Objeto Apontado
Nos exemplos abaixo, é ilustrada a diferença entre as operações de atribuição entre ponteiros (por exemplo, p : = q ) e a atribuição entre o conteúdo dos registros apontados pelos ponteiros (isto é: p^ : = q^).
var p,q: Lista;Dada a situação abaixo, chamada de (a):
Dada a situação (a), após a atribuição p : = q temos a representação abaixo (b). Esta atribuição só é válida para ponteiros do mesmo tipo e é a única operação entre ponteiros.
Dada a situação (a), após a atribuição p^ : = q^ temos a representação abaixo (c), onde o conteúdo é atribuido (lembre que p^ equivale a L.A[p]).
Manipulação de Registros em Listas Encadeadas Dinâmicas
Operações
em Listas Encadeadas Dinâmicas