Apontadores

Propaganda
Unidade de Ensino Descentralizada de Colatina
Tecnólogo em Redes de Computadores
PASCAL
Apontadores
Definição: Um apontador ou ponteiro é uma variável que armazena o endereço de outra
variável. Sua utilização é vasta em programas por dois motivos:
1. Algumas computações só são possíveis com a utilização de ponteiros
2. A utilização de ponteiros em geral simplifica a programação e aumenta a eficiência
do código executável, tornando-o mais rápido.
Esses motivos podem não estar muito claros agora, mas na medida em que o conteúdo
for avançando perceberemos com mais clareza a importância do uso de ponteiros.
Apontadores e Endereços
Vejamos alguns exemplos para ilustrar os conceitos. Seja x uma variável inteira e px uma
variável ponteiro. Em PASCAL, o operador addr fornece o endereço de uma variável.
Assim a atribuição abaixo é válida:
px := addr(x);
Suponha a seguinte seqüência de código:
x := 7;
px := addr(x);
A figura abaixo mostra esquematicamente a situação em uma memória hipotética de 256
posições endereçadas de 0 (0000) a 255 (FFFF). Suponha que a variável x tenha sido
alocada no endereço 2 da memória e px na posição 5 da memória. Assim, após a
execução das linhas acima teremos a seguinte situação:
Variável Endereço
Dado
0000
X
000F
7
F000
00FF
px
FF00
000F
FFFF
O operador ^ serve para acessar o valor da área de memória (variável) apontada pelo
ponteiro. Por exemplo, a atribuição:
px := addr(x);
px^ := 6;
1
Unidade de Ensino Descentralizada de Colatina
Tecnólogo em Redes de Computadores
coloca o valor 6 na variável apontada por px (coloca o valor 6 na área de memória cujo
endereço está armazenado em px), ou seja em x. Isto quer dizer que fazer x = 6 ao invés
de px^ = 6 surtiria o mesmo efeito.
Seja y uma variável inteira. Então a seqüência:
x := 20;
px := addr(x);
y := px^;
Surte o mesmo efeito de
x := 20;
y := x;
Quando temos uma variável do tipo apontador (px) que guarda o endereço de uma outra
variável (x), dizemos que px aponta para x.
Declaração de Apontadores
Assim como qualquer outra variável, um apontador necessita ser declarado:
x, y : integer;
px : ^integer;
Como sabemos, x, y : integer; declaram x e y como duas variáveis inteiras. Então
x, por exemplo, representará um espaço de memória para armazenar um inteiro. A
declaração px : ^integer; é a declaração do ponteiro (da variável) px. Esta
declaração significa que px é uma variável que guardará um endereço de um espaço de
memória e esta memória, por sua vez, é para armazenamento de números inteiros. De
maneira mais compacta, o que se diz nesta declaração é que px é um ponteiro para um
inteiro. Podemos ter ponteiros para qualquer tipo válido. O trecho:
P : ^real;
está declarando a variável p, como sendo ponteiro para real, ou seja, como uma variável
que guardará um endereço de um espaço de memória que armazena um valor do tipo
real. Perceba que o ^ na declaração só serve para indicar que a variável é um ponteiro
(guarda um endereço de memória). O uso do operador ^ em uma variável ponteiro, fora
de uma declaração, tem o significado dado anteriormente de obter o conteúdo do espaço
de memória apontado. Por exemplo, veja o código abaixo:
program ponteiro1;
var
x, y : integer;
px : ^integer; { aqui o ‘^’ soh serve para indicar que
px eh um ponteiro }
begin
x := 20;
px := addr(x);
y := px^ + 10; { aqui o ‘^’ serve para pegar o valor
apontado por px
end.
Neste caso o que se faz é que y receba o conteúdo de x somado com 10.
2
Unidade de Ensino Descentralizada de Colatina
Tecnólogo em Redes de Computadores
Não podemos esquecer que apontadores são variáveis. Assim sendo serão também
válidas expressões envolvendo variáveis apontadores. Por exemplo, se py é uma variável
do tipo ponteiro, então a expressão:
py := px;
copia o conteúdo de px (não o conteúdo do endereço apontado por px) para dentro de
py fazendo com que py passe a apontar para o mesmo local para onde px aponta. Por
exemplo, na seqüência abaixo, o conteúdo de x é atribuído indiretamente a y através dos
ponteiros:
program ponteiro2;
var
x, y : integer;
px, px2 : ^integer;
begin
x := 10;
px := addr(x);
px2 := px;
y := px2^;
end.
Vejamos esquematicamente na memória. Suponha que o endereço de memória de cada
variável é o número que está entre parênteses.
x := 10;
px := addr(x);
px2 := px;
y := px2^;
3
Unidade de Ensino Descentralizada de Colatina
Tecnólogo em Redes de Computadores
Exercícios
1)
Escreva um programa que leia um número do teclado, guarde este número em
uma variável. Depois faça um ponteiro apontar para a variável que guardou este número
e imprima-o na tela, acessando o valor através do ponteiro.
2)
Analise as seguintes seqüências de código. Verifique se estão corretas ou
incorretas. Caso estejam incorretas, apontem os prováveis erros. Para tanto, considere
a declaração das variáveis abaixo:
var a, b : integer;
c, d : ^integer;
a) c := a;
erro
b) c := addr(b);
d := c;
d^ := 10;
c) c := a^;
erro
d := 10 + c^;
erro
i) b := 1;
c := b^;
erro
c^ := a + c^;
j) a := 1;
c := addr(a);
for b:=1 to 10 do
c^ := c^ + 1;
d) d := c;
c := addr(a);
a := 10;
b := d^;
write(b);
k) c := addr(b);
b := 10;
write(c^);
e) c := addr(a);
readln(c);
erro
d := c;
b := d^;
m) a := 100;
c := addr(a);
while (a>0) do begin
c^ := c^ - 1;
write(a);
end;
f) b := 10;
c := addr(b);
write(c);
erro
g) c^ := 20;
h) b := 2;
c := addr(b);
c^ := c^ + 2;
l) read(c^);
n) c^ := 10;
d := c;
d^ := d^ + 10;
write(d^);
o) d := addr(c); erro
4
Unidade de Ensino Descentralizada de Colatina
Tecnólogo em Redes de Computadores
Qual o valor inicial de um apontador?
Observe o seguinte programa:
program ponteiro3;
var
x : integer;
px : ^integer;
begin
px^ := 10;
x := px^;
end.
O que há de errado neste programa? Basta construir o esquema na memória e observar:
px^ := 10;
Logo na primeira instrução percebemos que não há coerência na atribuição. Isso porque:
se px não aponta para nenhuma área de memória válida, como poderemos atribuir um
conteúdo para dentro desta área?
Devemos ter em mente que inicialmente em um apontador não há endereço válido algum,
mas sim um valor lixo, ou seja, este ponteiro aponta para uma posição desconhecida da
memória. Isso significa que se usarmos um ponteiro sem a sua prévia inicialização
tornamos a manipulação desse ponteiro uma provável fonte de erros graves no programa.
Situações como essas podem facilmente derrubar o programa ou mesmo o sistema
operacional.
Assim, para manipularmos apontadores, estes devem apontar sempre para um endereço
de memória previamente alocada pelo programa (através da declaração de variáveis ou
dinamicamente como veremos mais adiante).
Ponteiros para Registros
Como já citado anteriormente, quando se cria um registro em PASCAL, um novo tipo é
criado. Já que podem haver ponteiros para qualquer tipo válido, ponteiros para um tipo
definido em um registro é perfeitamente possível. Abaixo é dado um exemplo.
Program Ponteiro4;
Type Ponto = record
x : real;
y : real;
end;
var
p1 : Ponto;
ps : ^Ponto; { ps é um ponteiro para Ponto }
begin
ps := addr(p1); { faco ps apontar para p1 }
end.
5
Unidade de Ensino Descentralizada de Colatina
Tecnólogo em Redes de Computadores
Neste exemplo, foram declaradas as variáveis p1 e ps. A variável p1 foi declarada como
sendo do tipo Ponto e ps como sendo um ponteiro para Ponto. Em seguida fez-se ps
apontar para p1.
Acesso aos Campos de um Registro através de um Ponteiro
Seguindo ainda o exemplo anterior, se quiséssemos preencher os campos x e y de p1
com os valores 5 e 8, por exemplo, poderíamos fazer de maneira direta, como já
conhecemos:
p1.x := 5;
p1.y := 8;
Mas poderíamos também fazê-lo através do ponteiro ps, que aponta para p1, da seguinte
forma:
ps^.x := 5;
ps^.y := 8;
Percebe-se então que o uso do operador ^ é da mesma forma que já vimos, de modo que
se pegue o elemento apontado. A diferença é que o elemento apontado é do tipo de um
registro criado e para acessar um campo de uma variável registro, utilizamos, como já
sabido, o ‘.’ seguido do nome do campo.
Vetores de Ponteiros
Se podemos ter vetores de qualquer tipo válido, incluindo os tipos criados com registros, é
totalmente possível declarar um vetor de ponteiros. Isto significa que teríamos um vetor
de endereços de memória e, portanto, cada posição do vetor apontaria para uma
determinada área de memória. Supondo um vetor de ponteiros para real, poderíamos ter
o seguinte programa:
Program Ponteiro5;
Type Ponteiro = ^real;
Var
v : array [1..3] of Ponteiro; { Vetor de ponteiros
para real }
x, y, z, soma : real;
begin
x := 3.5;
y := 5.6;
z := 8.0,
v[0] := addr(x);
v[1] := addr(y);
v[2] := addr(z);
soma := v[0]^ + v[1]^ + v[2]^;
write(soma);
end.
Este programa imprimirá 17.1, que é a soma de x, y e z.
6
Download