Estrutura de Dados
Ponteiros
Professor Mário Dantas
Contribuição: Professor Marcelo Douglas
Introdução ao uso de Ponteiros
• Os ints guardam valores inteiros. Os floats guardam valores de
ponto flutuante. Os chars guardam caracteres.
• Ponteiros guardam endereços de memória.
Esta operação pode ser entendida pelo
compilador como “carregue o inteiro 55 no
endereço de memória 248440”.
int j;
j = 55;
55
?????
?????
?????
?????
248440
?????
Introdução ao uso de Ponteiros
• Estamos acostumados a trabalhar
com o “conteúdo armazenado nos
endereços de memória”, no
entanto podemos estender os
recursos de nossos programas ao
aprendermos a trabalhar com os
endereçamentos.
• Quando você anota o endereço de
um colega está criando um
ponteiro. O ponteiro é o papel.
Paulo Roberto
Rua Rio de janeiro,
nº 3455
Introdução ao uso de Ponteiros
• Qual é o sentido disto?
• Quando você anota o endereço de um colega, você vai usar
este endereço para achá-lo.
• O C funciona assim. Você anota o endereço de algo numa
variável ponteiro para depois usar.
• Da mesma maneira, uma agenda, onde são guardados
endereços de vários amigos, poderia ser vista como sendo uma
matriz de ponteiros no C.
Introdução ao uso de Ponteiros
• Um ponteiro também tem tipo. No C quando declaramos
ponteiros nós informamos ao compilador para que tipo de
variável vamos apontá-lo. Um ponteiro int aponta para um
inteiro, isto é, guarda o endereço de um inteiro.
• Para declarar um ponteiro temos a seguinte forma geral:
tipo_do_ponteiro = *nome_da_variável
• É o asterisco (*) que faz o compilador saber que aquela
variável não vai guardar um valor mas sim um endereço para
aquele tipo especificado.
Introdução ao uso de Ponteiros
• Exemplos de criação de ponteiros:
int *ptr;
• O exemplo declara que desejamos criar uma variável ponteiro
para armazenar o endereço de um inteiro.
• Eles ainda não foram inicializados (como toda variável do C
que é apenas declarada). Isto significa que eles apontam para
um lugar indefinido. Este lugar pode estar, por exemplo, na
porção da memória reservada ao sistema operacional do
computador.
Introdução ao uso de Ponteiros
• Usar o ponteiro nestas circunstâncias pode levar a um
travamento do micro, ou a algo pior.
• O ponteiro deve ser inicializado (apontado para algum lugar
conhecido) antes de ser usado. Isto é de suma importância!
• Se declararmos o ponteiro fora de qualquer função ele é
automaticamente inicializado com um valor que
garantidamente não aponta para nenhuma posição de
memória. Este valor é NULL.
Introdução ao uso de Ponteiros
• Para atribuir um valor a um ponteiro recém-criado poderíamos
igualá-lo a um valor de memória.
• Mas, como saber a posição na memória de uma variável do
nosso programa?
• Seria muito difícil saber o endereço de cada variável que
usamos, mesmo porque estes endereços são determinados
pelo compilador na hora da compilação e realocados na
execução.
Introdução ao uso de Ponteiros
• Para saber o endereço de uma variável basta usar o operador
&. Veja o exemplo:
int count=10;
int *pt;
pt=&count;
• Criamos um inteiro count com o valor 10 e um apontador para
um inteiro pt. A expressão &count nos dá o endereço de
count, o qual armazenamos em pt.
• Vejamos o programa completo:
Introdução ao uso de Ponteiros
Introdução ao uso de Ponteiros
• Como nós colocamos um endereço em ptr, ele está agora
"liberado" para ser usado.
• Podemos, por exemplo, alterar o valor de count usando ptr.
• Para tanto vamos usar o operador "inverso" do operador &.
• É o operador *. No exemplo acima, uma vez que fizemos
ptr=&count a expressão *ptr é equivalente ao próprio count.
• Isto significa que, se quisermos mudar o valor de count para
12, basta fazer *pt=12.
Introdução ao uso de Ponteiros
Introdução ao uso de Ponteiros
Fixando Conteúdo
tipo *variavel;
Cria uma variável ponteiro que apontará
para o endereço de memória do tipo
estabelecido.
variavel = &n1;
Faz com que a variavel do tipo ponteiro
aponte para o endereço de memória da
variavel n1 e não ao seu conteúdo.
*variavel = n2;
*variavel é a mesma coisa de n1, portanto
alterar *variavel altera n1.
Introdução ao uso de Ponteiros
• Qual o resultado do programa abaixo?
Introdução ao uso de Ponteiros
• O que faz cada linha do programa abaixo?
Aritmética de Ponteiros
Estrutura de Dados
Aritmética de Ponteiros
• Existem apenas duas operações aritméticas que podem ser
usadas com ponteiros: adição e subtração.
• Quando incrementamos um ponteiro ele passa a apontar para
o próximo valor do mesmo tipo para o qual o ponteiro aponta.
• Isto é, se temos um ponteiro para um inteiro e o
incrementamos ele passa a apontar para o próximo inteiro.
Aritmética de Ponteiros
• Para exemplificar consideremos p1 um ponteiro para um
inteiro com o valor atual de 2000. Assuma que os inteiros
ocupam 4 bytes de memória.
• Após a expressão:
p1++;
• Quanto será o valor de p1?
• p1 contém 2004 e não 2001. Cada vez que p1 é incrementado
ele aponta para o próximo inteiro.
Aritmética de Ponteiros
Aritmética de Ponteiros
• se você incrementa um ponteiro char* ele anda 1 byte na
memória e se você incrementa um ponteiro double* ele anda
8 bytes na memória.
• Este é mais um motivo pelo qual o compilador precisa saber o
tipo de um ponteiro.
• O mesmo princípio da adição é aplicado para a subtração.
Aritmética de Ponteiros
Aritmética de Ponteiros
• Você não está limitado a apenas incrementar e decrementar.
Você pode também somar ou subtrair inteiros de ponteiros.
p1 = p1 + 12;
• Faz p1 apontar para o décimo segundo elemento do tipo p1
adiante do elemento que ele está atualmente apontando.
…………
p1
1
2
3
4
11 12 13
Aritmética de Ponteiros
• É importante compreender que estamos falando de
operações com ponteiros e não de operações com o
conteúdo das variáveis para as quais eles apontam.
(*ptr)++
Incrementa o conteúdo da variável apontada por ptr.
ptr++
Aponta para a próxima posição onde ptr se encontra.
*(ptr+15) Acessa o conteúdo do ptr quinze posições adiante.
Aritmética de Ponteiros
O que não pode ser feito com ponteiros
• Além de adição e subtração entre um ponteiro e um
inteiro, nenhuma outra operação aritmética pode ser
efetuada com ponteiros.
• Você não pode multiplicar ou dividir ponteiros e não pode
adicionar ou subtrair o tipo float ou o tipo double a
ponteiros.
Teste o programa e
Informe o resultado
Aritmética de Ponteiros
• Uma outra operação, às vezes útil, é a comparação entre dois
ponteiros. Mas que informação recebemos quando
comparamos dois ponteiros?
• Em primeiro lugar, podemos saber se dois ponteiros são iguais
ou diferentes (== e !=). No caso de operações do tipo >, <, >= e
<= estamos comparando qual ponteiro aponta para uma
posição mais alta na memória.
• Então uma comparação entre ponteiros pode nos dizer qual
dos dois está "mais adiante" na memória. A comparação entre
dois ponteiros se escreve como a comparação entre outras
duas variáveis quaisquer.
Aritmética de Ponteiros
Exercícios de Fixação
Exercícios de Fixação
• Supondo que p é um ponteiro para um inteiro, explique a
diferença entre:
p+;
(*p)++;
*(p++)
• O que quer dizer *(p+10)?
Exercícios de Fixação
• Qual o valor de y
no final do
programa? Após
descobrir escreva
um comentário
em cada comando
de atribuição
explicando o que
ele faz.
Download

Introdução ao uso de Ponteiros