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.