Algoritmos e Estrutura
de Dados I
Revisão - Ponteiros
Prof.: Ricardo Argenton Ramos
Roteiro
Definição de Ponteiros;
Passagem de Argumentos por Valor e
Referência;
Retornando Dados de Funções;
Operadores - Direto (&) e Indireto (*);
Operações com Ponteiros.
Introdução
 Três razões para o uso de ponteiros:
Funções podem modificar seus argumentos;
Alocação dinâmica de memória
Aumentar a eficiência de algumas rotinas
 Cuidado ao utilizá-los
Ponteiros não inicializados
Erro do Windows
Ponteiros
Um Ponteiro é uma variável que contém o
endereço de memória de outra variável.
É possível ter um ponteiro para qualquer
tipo de variável.
Passagem por Valor
 Em C todos os argumentos (parâmetros) de
funções são passados por valor
 Isso significa que uma cópia dos valores dos
argumentos é dada à função chamada, e ela
cria outras variáveis temporárias para
armazenar esses valores
 O ponto principal é que, em C, uma função
chamada não pode alterar o valor de uma
variável da função que chama; ela só pode
alterar a sua cópia temporária.
Passagem de Argumentos por Valor
Imprime o valor e o endereço das variáveis a e b
antes e após chamar a função.
main(){
int a, b;
a = 5;
b = 5;
Cria duas variáveis a e b que serão
utilizadas como parâmetro da função
Incrementa().
printf("\n O Valor de a: %d , e o seu endereco e:
%d\n", a, &a);
printf("\n O Valor de b: %d , e o seu endereco e:
%d\n", b, &b);
incrementa(a,b);
Invoca a função para incrementar os valores de a e b
printf("\n O Valor de a: %d , e o seu endereco e:
%d\n", a, &a);
printf("\n O Valor de b: %d , e o seu endereco e:
%d\n", b, &b);
}
Cria duas novas variáveis a e b, incrementa
elas em 2 unidades e imprime seus valores e endereços.
int incrementa(int a, int b){
a = a + 2;
b = b + 2;
printf("\n O Valor de a: %d , e o seu
endereco e: %d\n", a, &a);
printf("\n O Valor de b: %d , e o seu
endereco e: %d\n", b, &b);
}
Passagem de Argumentos por Valor
main(){
int a, b;
a = 5;
b = 5;
printf("\n O Valor de a: %d ,
printf("\n O Valor de b: %d ,
incrementa(a,b);
printf ("--- Depois de chamar
printf("\n O Valor de a: %d ,
printf("\n O Valor de b: %d ,
}
int incrementa(int a, int b){
a = a + 2;
b = b + 2;
printf("\n O Valor de a: %d ,
printf("\n O Valor de b: %d ,
}
a
b
e o seu endereco e: %d\n", a, &a);
e o seu endereco e: %d\n", b, &b);
a funcao ---\n");
e o seu endereco e: %d\n", a, &a);
e o seu endereco e: %d\n", b, &b);
e o seu endereco e: %d\n", a, &a);
e o seu endereco e: %d\n", b, &b);
Passagem de Argumentos por Valor
main(){
int a, b;
a = 5;
b = 5;
printf("\n O Valor de a: %d ,
printf("\n O Valor de b: %d ,
incrementa(a,b);
printf ("--- Depois de chamar
printf("\n O Valor de a: %d ,
printf("\n O Valor de b: %d ,
}
int incrementa(int a, int b){
a = a + 2;
b = b + 2;
printf("\n O Valor de a: %d ,
printf("\n O Valor de b: %d ,
}
a
b
5
5
e o seu endereco e: %d\n", a, &a);
e o seu endereco e: %d\n", b, &b);
a funcao ---\n");
e o seu endereco e: %d\n", a, &a);
e o seu endereco e: %d\n", b, &b);
e o seu endereco e: %d\n", a, &a);
e o seu endereco e: %d\n", b, &b);
Passagem de Argumentos por Valor
main(){
a
5
int a, b;
b
5
a = 5;
b = 5;
a
75
printf("\n O Valor de a: %d , e o seu endereco e: %d\n", a, &a);
b
5
7
printf("\n O Valor de b: %d , e o seu endereco e: %d\n", b, &b);
incrementa(a,b);
printf ("--- Depois de chamar a funcao ---\n");
printf("\n O Valor de a: %d , e o seu endereco e: %d\n", a, &a);
printf("\n O Valor de b: %d , e o seu endereco e: %d\n", b, &b);
}
int incrementa(int a, int b){ Dois valores inteiros são passados para
a = a + 2;
a função, mas ela não sabe quem são
b = b + 2;
(onde estão) essas variáveis.
printf("\n O Valor de a: %d , e o seu endereco e: %d\n", a, &a);
momento
ela e:
cria%d\n",
duas variáveis
printf("\n O Valor de b: %d ,Nesse
e o seu
endereco
b, &b);
para armazenar os valores inteiros
}
que foram recebidos
Executando....
O que são Ponteiros ?
 Proporciona um modo de acesso a variáveis
sem referenciá-las diretamente.
 O mecanismo usado para isso é o endereço da
variável. Esse endereço age com um
intermediário entre a variável e o programa que
a acessa
 Basicamente, um ponteiro é uma representação
simbólica de um endereço
 São usados onde a passagem de valores é
difícil ou indesejável
Ponteiros Variáveis
 Um ponteiro variável possui como conteúdo um
endereço de memória. Esse endereço é a localização de
uma outra variável de memória
 Diz-se que uma variável aponta para outra quando a
primeira possui o endereço da segunda
endereços
1
2
3
4
5
Luiza
1
Ponteiros Constantes
Ponteiros variáveis são variáveis que
armazenam endereços de memória
Ponteiros constantes são endereços de
memória
O nome de uma matriz é um exemplo de um
ponteiro constante
Razões para usar ponteiros
Deseja modificar os argumentos que
recebem
Para criar estruturas de dados complexas,
como listas encadeadas e árvores binárias
Compilam mais rapidamente, tornando o
código mais eficiente
Retornando dados de Funções
O primeiro exemplo mostrará como que
uma função pode alterar os valores dos
argumentos da função chamadora
Vamos iniciar com uma nova versão do
programa mostrado anteriormente.
Cria duas variáveis a e b, atribui o valor
5 a cada uma delas, imprime o valor
e endereço de cada uma.
Exemplo de ponteiros
main() {
int a, b;
a = 5;
b = 5;
printf ("--- Antes de chamar a funcao ---\n");
printf("\n O Valor de a: %d , e o seu endereco e: %d\n", a, &a);
printf("\n O Valor de b: %d , e o seu endereco e: %d\n", b, &b);
Chama a função incrementa passando como parâmetro
o endereço de memória das variáveis a e b.
incrementa(&a,&b);
printf ("--- Depois de chamar a funcao ---\n");
printf("\n O Valor de a: %d , e o seu endereco e: %d\n", a, &a);
printf("\n O Valor de b: %d , e o seu endereco e: %d\n\n\n", b, &b);
}
incrementa(int *a, int *b)
*a = *a + 2;
*b = *b + 2;
printf("\n--- Dentro da
printf("\n\n O Valor do
conteudo de a:%d \n",
printf("\n\n O Valor do
conteudo de b:%d \n",
{
A função incrementa() possui como parâmetro dois
ponteiros para os endereços de memória que receberá
como parâmetro. Qualquer operação com esses
ponteiros afetará o valor das variáveis correspondentes.
funcao ---");
ponteiro a: %d , seu endereco e: %d, e
a, &a, *a);
ponteiro b: %d , seu endereco e: %d, e
b, &b, *b);
Exemplo de ponteiros
main() {
int a, b;
a = 5;
b = 5;
printf ("--- Antes de chamar a funcao ---\n");
printf("\n O Valor de a: %d , e o seu endereco e:
printf("\n O Valor de b: %d , e o seu endereco e:
1
2
3
4
5
%d\n",
6
%d\n",
a
b
*a
*b
57
75
1
2
a, &a);
b, &b);
incrementa(&a,&b);
printf ("--- Depois de chamar a funcao ---\n");
printf("\n O Valor de a: %d , e o seu endereco e: %d\n", a, &a);
printf("\n O Valor de b: %d , e o seu endereco e: %d\n\n\n", b, &b);
}
incrementa(int *a, int *b)
*a = *a + 2;
*b = *b + 2;
printf("\n--- Dentro da
printf("\n\n O Valor do
conteudo de a:%d \n",
printf("\n\n O Valor do
conteudo de b:%d \n",
Na chamada da função, ela cria duas variáveis do tipo
{ ponteiro que armazenarão endereços do tipo inteiro.
As operações serão realizadas sobre esses endereços.
funcao ---");
ponteiro a: %d , seu endereco e: %d, e
a, &a, *a);
ponteiro b: %d , seu endereco e: %d, e
b, &b, *b);
Executando...
Pontos Importantes
incrementa(&a,&b);
Função é chamada, passando
para ela dois endereços de variáveis
incrementa(int *a, int *b) { Os endereços recebidos serão armazenados
*a = *a + 2;
*b = *b + 2;
em variáveis ponteiros.
O conteúdo da variável apontada recebe
ele mesmo acrescido de 2.
printf("\n\n O Valor do ponteiro a: %d , seu endereco e:
%d, e conteudo de a:%d \n",
a, &a, *a);
O valor do ponteiro  a
O endereço do ponteiro  &a
O valor da variável apontada pelo ponteiro  *a
Exercício
Elaborar um programa que faça a
atribuição de novos valores a duas
variáveis (do tipo int) por referência sem
utilizar uma função.
Outro Exemplo
O próximo exemplo difere do primeiro no
sentido de que as variáveis do main() não
possuem valores até que a função
altera2() é chamada.
A única coisa que essa função faz é
fornecer valores às variáveis criadas no
main()
Devolve2.c
Cria duas variáveis e não atribui valor à
elas. Chama a função altera2() passando
os endereços dessas variáveis.
main() {
int x,y;
altera2(&x,&y);
printf("\nO primeiro e %d, o segundo e %d\n\.", x,y);
}
altera2(int *px, int *py)
{
*px = 3;
*py = 5;
}
A função cria variáveis do tipo ponteiro
que apontarão para os endereços que serão
recebidos por parâmetro. Qualquer operação
com esses ponteiros afetará o valor das variáveis
apontadas.
Executando...
Operador e Operando
Exemplo
a++  operador ++, operando a
a – b  operador -, operandos a e b
&a  operador & e operando a
*p  operador * e operando p
Operadores - Direto (&) e Indireto (*)
 Para declarar variáveis do tipo Ponteiro
int *px, *py;
Isso cria duas variáveis do tipo ponteiro. Essas
variáveis podem conter endereços de variáveis do tipo
int.
 Operadores
& - operador direto que retorna o endereço da variável
operando
* - operador indireto que retorna o conteúdo da variável
localizada no endereço.
 Se no programa anterior mandássemos imprimir
o valor dos ponteiros...
main() {
int x,y;
altera2(&x,&y);
printf("\nO primeiro e %d, o segundo e %d\n\.", x,y);
}
Essas variáveis do tipo ponteiro apontam
(endereçam) para as variáveis x e y.
Ao imprimir, o valor das variáveis
será mostrado.
altera2(int *px, int *py)
{
*px = 3;
*py = 5;
printf("\n\nO primeiro ponteiro e %d, o segundo
ponteiro e %d\n\n\n.", *px, *py);
}
Executando...
Considerações
 Você deve se assegurar que suas variáveis
ponteiro sempre apontam para variáveis do
mesmo tipo
 A função passa indiretamente os valores 3 e 5
para as variáveis x e y. isso é indireto porque a
função não conhece os nomes das variáveis,
assim ela usa seus endereços
 main() acessa as variáveis x e y de um certo
modo, enquanto altera2() de outro. main()
denomina-as de x e y, enquanto que altera2()
denomina-as de px e py.
Exemplo Prático
 Rotina de ordenação não poderia permutar dois
elementos fora de ordem com uma função de
troca...
troca (x,y)
troca (int *ax, int *ay)
{
{ int temp;
int temp;
temp = *ax
temp = x;
};
x = y;
*ax = *ay;
y = temp;
*ay = temp;
};
 A solução é utilizar ponteiros para que a função
realmente altere a ordem dos elementos do
programa chamador
main() {
int menor = 6, maior = 5;
Cria duas variáveis e as inicializa
com os valores 6 e 5.
printf ("\n (main) valor de menor %d, valor do maior: %d",
menor,maior);
Se o valor da variável menor é > que o valor
da variável maior, invoca a função troca
if (menor > maior) {
para permutar esses valores dessas variáveis
troca(&menor,&maior);
printf ("\n (depois da chamada) valor do menor: %d, valor do maior:
%d\n\n", menor,maior);
}
}
void troca(int *menor, int *maior) {
int temp;
temp = *maior;
*maior = *menor;
*menor = temp;
}
Função que recebe como parâmetro dois
endereços para variáveis do tipo int.
Cria uma variável temp para permutar
os valores que estão sendo apontados.
Exercício
Implementem um programa que possua
duas variáveis (a e b) do tipo int.
Deve haver uma função que some a em b,
uma outra função que some b em a e uma
outra que subtraia b de a.
Note que o valor das variáveis do main é
que devem ser alterados
Operações com Ponteiros
 São cinco as operações que podem ser feitas
com ponteiros
 O próximo programa mostra essas operações
mostrando o valor do ponteiro, o valor
armazenado na variável apontada e o endereço
do próprio ponteiro.
 O próximo exemplo também mostra o problema
que pode ocorrer quando não se cuida dos
endereçamentos...
operptr.c
main() {
int x=5, y=6;
int *px, *py;
px = &x;
py = &y;
printf ("--- Valor ----- Ponteiro -- Endereco do ponteiro\n\n");
printf("px = %u, *px = %d, &px = %u\n", px, *px, &px);
printf("py = %u, *py = %d, &py = %u\n\n", py, *py, &py);
py++;
printf ("Incrementou py em uma unidade de inteiro\n\n");
printf("px = %u, *px = %d, &px = %u\n", px, *px, &px);
printf("py = %u, *py = %d, &py = %u\n", py, *py, &py);
printf ("py - px = %u\n", py - px);
if (px < py) {
printf("py - px = %u\n\n", py - px);
}
else {
printf ("px - py = %u\n\n", px - py);
}
}
Executando...
main() {
int x=5, y=6;
int *px, *py;
6684148
6684144
6684140
6684136
px = &x;
py = &y;
printf ("--- Valor ----- Ponteiro -- Endereco do ponteiro\n\n");
printf("px = %u, *px = %d, &px = %u\n", px, *px, &px);
printf("py = %u, *py = %d, &py = %u\n\n", py, *py, &py);
py++;
printf ("Incrementou py em uma unidade de inteiro\n\n");
printf("px = %u, *px = %d, &px = %u\n", px, *px, &px);
printf("py = %u, *py = %d, &py = %u\n", py, *py, &py);
printf ("py - px = %u\n", py - px);
if (px < py) {
printf("py - px = %u\n\n", py - px);
}
else {
printf ("px - py = %u\n\n", px - py);
}
x
y
5
56
*px
*py
6684148
int
6684148
6684144
int
As Operações
 As operações que podem ser feitas com
ponteiros são:
Atribuição
px = &x
Incremento de unidades (tipos)
px++
Soma ou subtração
py – px
(6684148 – 6684144 = 1)
px = px + 3; (6684148 + 3 = 6684160)
Comparações (>=, <=, > , <, ==, !=, null)
Somente quando os dois operandos são ponteiros e
de mesmo tipo.
Exercício
Faça um programa que contenha 4
variáveis (a, b, c, d) com os valores
iniciais 1, 2, 3 e 4 respectivamente, crie
então 4 ponteiros (na função main).
Faça uma função especifica para que os 4
ponteiros apontem para a variável (d). Imprima os
valores apontados pelos ponteiros.
Faça uma segunda função que atribua (por
referência) o valor de a em b e de c em d (b=a e
d=c).
Faça uma terceira função que compare os
ponteiros e casos sejam maior que zero dever ser
decrementados e se forem menor que zero devem
ser incrementados.
Download

Ponteiros