Apontadores ou Ponteiros
T.L.P. 11º Ano
Conceitos básicos
 Quando se define uma variável é guardado um espaço em
memória do tamanho do tipo da variável
int x;
2 bytes
float y;
4 bytes
char n[10];
10 bytes
Miguela Fernandes
2
Conceitos básicos
Exemplo
int x= 10;
12
100 101 102 103 104 105
 Não esquecer que ocupa 2 bytes. Então x está no endereço 102
 O operador de endereço como já é vosso conhecido é &
Então o endereço de x posso obtê-lo da seguinte forma:
printf(“Endereço de x = %d ”, &x);
// Endereço de x = 102
Exemplo char z =‘A’
12
‘A’
100 101 102 103 104 105
printf(“Endereço de z = %d ”, &z);
// Endereço de x = 105
Miguela Fernandes
3
Apontadores/Ponteiros
Os apontadores são variáveis que guardam os endereços
de memória (&) de outras variáveis.
Então podemos fazer ptr = &x //
x
12
100 101 102
Estou a atribuir o endereço de x a ptr
z
‘A’
104 105
Miguela Fernandes
ptr
102
4
Declarar Ponteiros
Sintaxe
tipo_dado *nome_ponteiro;
Exemplo:
int x;
int *ptr;
/* compilador sabe que ptr
ponteiro para inteiro */
é um
*- O asterisco indica que é um ponteiro
Exemplos
char x, *p, y, * ap;
Float *p_num, num;
//char * p ou char*
Miguela Fernandes
p
5
Operadores dos Ponteiros
* desreferenciador
Devolve o valor apontado pelo ponteiro.
& referenciador
Devolve o endereço de memória do seu operando.
Precedência: Tanto o & como o * possuem precedência maior que qualquer outro
operadore, com excepção do menos unário, que possui a mesma.
Miguela Fernandes
6
Iniciar Ponteiros
Já vimos que o operador “&” retorna
endereço de uma variável
Para iniciar ponteiros temos que:
int x = 10, *ptr;
ptr = &x;
//Defino a var e o ponteiro
//Inicio
o ponteiro
printf(“&x: %x ptr: %x”, &x, ptr);
&x: 0x03062fd8
Miguela Fernandes
ptr: 0x03062fd8
7
Iniciar Ponteiros c/ NULL
 Para iniciar ponteiros temos que:
int x = 10, *ptr;
ptr = &x;
//Defino a var e o ponteiro
//Inicio o ponteiro
Quando não pretendo iniciar logo o
ponteiro com valores tenho de:
ptr = NULL
Miguela Fernandes
8
Manipular Ponteiros
 Imprimir o conteúdo de uma variável
x
10
int x = 10, *ptr = &x;
printf(“ x = %d”, x); // x = 10
102
ptr
 Imprimir o conteúdo de um ponteiro
printf(“ ptr = %d”,ptr); // x = 102
102
200
 Imprimir o valor para onde ele aponta
printf(“ x = %d”, *ptr); // x = 10
Miguela Fernandes
9
Manipular Ponteiros
Se py e px são pointers para inteiros, então podemos fazer a seguinte
declaração:
py=px;
py fica a apontar p/ o mesmo que px
void main(){
int x,*px,*py;
x=9;
px=&x;
py=px;
printf("x= %d\n",x);
printf("&x= %d\n",&x);
printf("px= %d\n",px);
printf("*px= %d\n",*px);
printf("*py= %d\n",*py);
}
Miguela Fernandes
10
Exercício 1
1- Declara uma variável para guardar a tua idade e inicial um ponteiro
para a variável idade.
2- O que estou a fazer com seguinte declaração:
int* x, y, z;
3- Fazer um programa que veja os endereços de memória de uma
variável do tipo inteiro, char e float. Pretende-se que o faças 1º sem
recorrer a ponteiros e depois com recurso a estes.
Miguela Fernandes
11
Cuidado com os tipos de dados
Os ponteiros são variáveis tipadas:
(int *) ≠ (float *) ≠ (char *)
void main() {
int *p1, x;
float *p2, y;
p1 = &x; /*
p2 = &y; /*
p1 = &z; /*
p2 = &x; /*
}
OK */
OK */
Erro */
Erro */
Um apontador para o tipo xpty, avança sempre o sizeof(xpty)
Miguela Fernandes
12
Cuidado com os tipos de dados
c
i
‘A’
12
100
101
100
140
102
103
102
141
ptr_c
142
f
3.1415
104
105
106
107
108
109
110
111
112
107
143
ptr_i
144
145
146
147
148
149
150
151
152
ptr_f
Sizeof(char) ≠ Sizeof(int) ≠ Sizeof(float)
Não posso fazer:
ptr_c = &i; ptr_i=&f;
Miguela Fernandes
13
Exercício 2
Pratique a declaração e utilização de ponteiros.




defina e inicialize uma variável inteira
defina um ponteiro para inteiro
modifique o valor da variável através do ponteiro
verifique os novos valores da variável usando printf
Miguela Fernandes
14
Ponteiros Genéricos
Um ponteiro genérico é um ponteiro que pode
apontar para qualquer tipo de dado
Define-se um ponteiro genérico utilizando o tipo
void:
void *ptr;
int x=10;
float y=88.2;
ptr = &x;
ptr = &f;
/* neste caso ptr aponta para um inteiro */
/* agora para um float */
Miguela Fernandes
15
Ponteiros Genéricos
O tipo de dado apontado por um void pointer deve
ser controlado pelo utilizador através do cast
Sintaxe:
* (tipo *) ponteiro
ptr = &x;
printf(“Inteiro: %d\n”, *(int *) ptr );
/* Inteiro = 10*/
ptr = &f;
printf(“Float: %4.2f\n”, *(float *) ptr );
/*Float = 88.20*/11
Miguela Fernandes
16
Ponteiros e Vectores
Relembrar:
O nome de um vector é um ponteiro (constante) para o 1º elemento do
vector
Exemplo:
int v[10];
v == &v[0]
Int *ptr;
ptr= &v[0]
// ou ptr =v;
Então:
*(ptr+1) é igual a v[1],
*(ptr+2) é igual a v[2],
*(ptr+n) == v[n]
Miguela Fernandes
17
Ponteiros e Vectores
Não esquecer:
 float x[20]
x é um apontador constante que
endereça o primeiro elemento do vector, como tal,
não é possível mudar o seu valor.
Exemplo:
float x[10], y[10];
float *ptr_f;
x = y;
/* NUNCA ERRO: x é constante ! */
ptr_f = x; /* SEMPRE OK */
Miguela Fernandes
18
Ponteiros e Vectores
Pode referenciar-se os elementos de um vector
através de ponteiros:
float x[] = { 11.0, 2.0, 5.4, 7.987 };
float *ptr_f;
ptr_f= &x[1];
printf(“%f”, *ptr_f);
/*
2.0 */
printf(“%f”, *(ptr_f +1)); /*
5.4 */
Miguela Fernandes
19
Ponteiros e Vectores
Pode utilizar-se ponteiros e parênteses rectos:
float x[] = { 11.0, 2.0, 5.4, 7.987 };
float *ptr_f;
ptr_f = &x[1];
printf(“%f”, ptr_f[0]);
/* ==> 2.0 */
Nota
O valor entre chavetas é o deslocamento a ser
considerado a partir do endereço de referência
ptr_f[n] => indica enésimo elemento a partir de
Miguela Fernandes
20
Ponteiros e Vectores
Exemplo 1
/*exercicio ptr_5*/
#include <stdio.h>
#include <conio.h>
#define TAM 10
char v[TAM] = "0123456789";
void main()
{
clrscr();
int i;
for (i = 0; i < TAM; ++i) {
printf("&v[i]=%p (v+i)=%p v[i]=%c\n", &v[i], (v+i), v[i]);
}
getch();
}
Miguela Fernandes
21
Ponteiros e Vectores
Exemplo 2
Programa que dá o numero de elementos de um vector antes de
encontrar o 0.
#include <stdio.h>
#include <conio.h>
void main()
{
int v[] = {4, 5, 8, 9, 8, 1, 0, 1, 9, 3};
int i = 0;
while (v[i] != 0)
++i;
printf("Nº de elementos antes de 0
%d\n",i);
getch();
}
/*exercício n 6*/
#include <stdio.h>
#include <conio.h>
void main()
{
int v[] = {4, 5, 8, 9, 8, 1, 0, 1, 9, 3};
int *ptr;
ptr=v;
while ((*ptr) != 0)
++ptr;
printf("Nº de elementos antes de 0 %d\n",ptr-v);
getch();
}
Miguela Fernandes
22
Aritmética de Ponteiros
É possível fazer operações aritméticas e
relacionais entre ponteiros e inteiros
 Soma ou subtracção
int x[10], *ptr;
ptr[2]
equivale a *(ptr+2)
*(ptr + n) acede ao conteúdo de n elementos a frente
*(ptr - n) acede ao conteúdo de n elementos atrás
ptr++
acede ao próximo endereço elemento vector *
ptr-acede ao endereço anterior do vector *
* Não esquecer que avança o tamanho do tipo int 2 bytes, float 4
bytes, etc.
Miguela Fernandes
23
Aritmética de Ponteiros
vect
2
100
0
1
3
5
..
..
..
102
104
106
108
110
112
114
..
..
…
……
148
149
..
..
..
150
151
152
100
140
ptr
141
142
143
144
145
146
147
Quais os seguintes resultados: ptr_10
printf(“%d”, ptr);
printf(“%d”, *ptr);
printf(“%d”, ++ptr); // Porque não printf(“%d”, ptr++); ???
printf(“%d”, vect [1]);
printf(“%d”, (*ptr)++);
printf(“%d”, vect [1]);
printf(“%d”, *(ptr++));
printf(“%d”, *(ptr+2));
printf(“%d”, ptr); Miguela Fernandes
24
Aritmética de Ponteiros
vect
2
100
0
1
3
5
..
..
..
102
104
106
108
110
112
114
..
..
…
……
148
149
..
..
..
150
151
152
100
140
141
142
143
144
145
146
147
ptr
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
ptr);
//100
*ptr);
// 2
++ptr);
vect [1]);
(*ptr)++);
vect [1]);
*(ptr++));
*(ptr+2));
ptr); Miguela Fernandes
25
Aritmética de Ponteiros
vect
2
100
0
1
3
5
..
..
..
..
102
104
106
108
110
112
114
..
…
……
148
149
..
..
..
150
151
152
102
140
141
142
143
144
145
146
147
ptr
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
ptr);
*ptr);
++ptr);
vect [1]);
(*ptr)++);
vect [1]);
*(ptr++));
*(ptr+2));
ptr); Miguela Fernandes
//100
// 2
// 2
// 0
// 0
26
Aritmética de Ponteiros
vect
2
100
1
1
3
5
..
..
..
..
102
104
106
108
110
112
114
..
…
……
148
149
..
..
..
150
151
152
102
140
141
142
143
144
145
146
147
ptr
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
ptr);
*ptr);
++ptr);
vect [1]);
(*ptr)++);
vect [1]);
*(ptr++));
*(ptr+2));
ptr); Miguela Fernandes
//100
// 2
// 2
// 0
// 0
// 1
27
Aritmética de Ponteiros
vect
2
100
1
1
3
5
..
..
..
102
104
106
108
110
112
114
..
..
…
……
148
149
..
..
..
150
151
152
104
140
141
142
143
144
145
146
147
ptr printf(“%d”, ptr);
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
*ptr);
++ptr);
vect [1]);
(*ptr)++);
vect [1]);
*(ptr++));
*(ptr+2));
ptr); Miguela Fernandes
//100
// 2
// 2
// 0
// 0
// 1
// 1
28
Aritmética de Ponteiros
vect
2
100
1
1
3
5
..
..
..
102
104
106
108
110
112
114
..
..
…
……
148
149
..
..
..
150
151
152
104
140
141
142
143
144
145
146
147
ptr printf(“%d”, ptr);
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
printf(“%d”,
//100
*ptr);
// 2
++ptr);
// 2
vect [1]);
// 0
(*ptr)++);
// 0
vect [1]);
// 1
*(ptr++));
// 1
*(ptr+2));
// 5
ptr); Miguela Fernandes // 104
29
Utilizando Ponteiros
void main() {
int x = 10;
int *pi, *pj;
pi = &x;/* *pi == 10 */
pj = pi;/* *pj == 10 */
(*pi)++;/* (*pi, *pj, x) == 11 */
(*pj)++; /* (*pi, *pj, x) == 12 */
printf(“%d”, x); /* ==> 12 */
}
Miguela Fernandes
30
Utilizando Ponteiros
void main() {
int x = 10;
int *pi;
pi = &x;/* *pi == 10 */
(*pi)++;/* *pi == 11 */
printf(“%d”, x);
}
==> 11
Ao alterar *pi estamos a alterar o conteúdo de x
Miguela Fernandes
31
Exemplo
void
{
int
int
int
main ()
arint[] =
size = 7;
i, *pi;
{ 1,2,3,4,5,6,7 };
/* tamanho do array */
for (pi=arint, i=0; i < size; i++, pi++)
printf(“ %d “, *pi);
}
==> 1 2 3 4 5 6 7
Miguela Fernandes
32
Exemplo - variação
void main () {
int arint[] = { 1,2,3,4,5,6,7 };
int size = 7;
/* tamanho do array */
int i, *pi;
pi = arint;
printf(“ %d “, *pi); pi += 2;
printf(“ %d “, *pi); pi += 2;
printf(“ %d “, *pi); pi += 2;
printf(“ %d “, *pi);
}
==> 1 3 5 7
Miguela Fernandes
33
Exemplo - variação
void
{
int
int
int
main ()
arint[] =
size = 7;
i, *pi;
{ 1,2,3,4,5,6,7 };
/* tamanho do array */
for (pi=arint, i=0; i < size; i++)
printf(“ %d “, *pi++);
}
==> 1 2 3 4 5 6 7
Miguela Fernandes
34
Operações Válidas Sobre Ponteiros
Podemos:
 somar ou subtrair um inteiro a um ponteiro (ptr ± int)
 incrementar ou decrementar ponteiros (ptr++, ptr--)
 subtrair ponteiros (produz um inteiro)
(ptr1 – ptr2)
 comparar ponteiros ( >, >=, <, <=, == )
Não podemos:
 somar ponteiros
(ptr1 + ptr2)
 multiplicar ou dividir ponteiros (ptr1*ptr2, ptr1/ptr2)
 usar
ponteiros com double ou float (pi ± 2.0)
Miguela Fernandes
35
Exercício 3
Escreva um programa que imprima um vector de
inteiros na ordem inversa endereçando os
elementos com um ponteiro
Miguela Fernandes
36
Cuidados...
C não controla os limites dos arrays, o
programador deve fazê-lo
Ex:
 encontrar o erro:
void main () {
int arint[] = { 1,2,3,4,5,6,7 };
int size = 7, i, *pi;
for (pi=arint, i=0; i < size; i++, pi += 2)
printf(“ %d “, *pi);
}
Miguela Fernandes
37
Cuidados...
void main ()
{
int arint[] = { 1,2,3,4,5,6,7 };
int size = 10;
int i;
for (pi=arint, i=0; i < size; i++)
printf(“ %d “, arint[i]);
}
Miguela Fernandes
38
Cuidados...
Um ponteiro deve sempre apontar para um local
válido antes de ser utilizado
Ex:
void main ()
{
int i=10, *pi;
*pi = i;
}
/*erro ! pi nao tem endereco valido*/
Miguela Fernandes
39
Ponteiros e Strings
strings são vectores de caracteres e podem ser
acedidos através de char *
void main ()
{
char str[]=“abcdef”, *pc;
for (pc = str; *pc != ‘\0’; pc++)
putchar(*pc);
}
==> abcdef
o incremento de pc o posiciona sobre o
próximo caracter (byte a byte)
Miguela Fernandes
40
Ponteiros e Strings
operações sobre strings com ponteiros
void StrCpy (char *destino, char *origem)
{
while (*origem)
/* *origem==0 encerra while */
{
*destino=*origem;
origem
origem++;
destino++;
a b c d e \0
}
*destino='\0';
a b
}
destino
Miguela Fernandes
41
Ponteiros e Strings
variação de strcpy:
void strcpy (char *destino, char *origem)
{
while ((*destino = *origem) != ‘\0’)
destino++, origem++;
}
Miguela Fernandes
42
Arrays Multidimensionais
Arrays podem ter diversas dimensões, cada uma
identificada por um par de colchetes na
declaração
Ex:
[0,0]
char matriz[5][10];
 declara uma matriz de 5 linhas e 10 colunas:
 na memória, entretanto, os caracteres são
armazenados linearmente:
[0,0]
[0,9]
[4,9]
[1,9]
Miguela Fernandes
[4,9]
43
Array de Caracteres
Percorrendo array com ponteiro:
void main () {
char matriz[5][10];
char *pc;
int i;
for (i=0, pc=matriz[0]; i < 50; i++, pc++)
*pc = ‘ ‘;
}
Miguela Fernandes
44
Array de Caracteres
Percorrendo array com indices:
void main () {
char matriz[5][10];
int i, j;
for (i=0, j=0; i<5; i++)
for (; j<10; j++)
matriz[i][j] = ‘ ‘;
}
as colunas (dimensões mais a direita)
mudam mais rápido
Miguela Fernandes
45
Array de Inteiros
Exemplo: considere o problema de
conversão de data dia_do_ano: um dos 365
dias do ano, convertido a partir do mes e dia
do mes
Tabela que indica dias dos meses incluindo
bissexto
static char tabela_dias[2][13] =
{
{ 0,31,28,31,30,31,30,31,31,30,31,30,31 }
{ 0,31,29,31,30,31,30,31,31,30,31,30,31 }
};
Miguela Fernandes
46
Conversão de Data
Organização lógica e física da tabela:
tabela_dias
0
31
28
31
30
31
31
30
31
30
31
30
31
0
31
29
31
30
31
31
30
31
30
31
30
31
28
31 ...
31
30
memória
0
31
0
31
28
Miguela Fernandes
31 ...
31
47
Conversão de Data
 /* dia_do_ano: calcula dia do ano a partir do dia do
mes */
int dia_do_ano(int ano, int mes, int dia)
{
int i, bis;
bis = (ano%4)==0 && (ano%100)!=0 || (ano%400)==0;
for (i = 1; i < mes; i++)
dia += tabela_dias[bis][i];
return dia;
}
Miguela Fernandes
48
Array de Strings
Neste caso, cada elemento do array é um ponteiro
para um caracter
Declaração:
char *arstr[] = {“Joao”, “Maria”, “Antonio”,
“Zacarias”, “Carlos”};
arstr é um array de ponteiros para char, iniciado
com os strings indicados
Miguela Fernandes
49
Array de Strings
Comparando array de string com matriz de char
char *as[]=
{“Joao”,“Maria”,“Antonio”,“Zacarias”,“Carlos”};
char ma[5][10]=
{“Joao”,“Maria”,“Antonio”,“Zacarias”,“Carlos”};
Ponteiros (as)
“Joao”
“Maria”
“Antonio”
“Zacarias”
“Carlos”
Matriz (ma)
J
M
A
Z
C
Miguela Fernandes
o
a
n
a
a
a
r
t
c
r
o \0
i a \0
o n i o \0
a r i a s \0
l o s \0
50
Cuidados com Strings
É comum esquecer de alocar uma área para
armazenamento de caracteres
void main() {
char *pc; char str[] = “Um string”;
strcpy(pc, str);
/* erro! pc indeterminado
*/
...
}
Miguela Fernandes
51
Ponteiros para Ponteiros
É possível definir ponteiros para ponteiros até
um nível arbitrário de indirecção
Ex:
char *pc; /* ponteiro para char */
char **ppc;/* ponteiro para ponteiro para char */
pc = “teste”;
ppc = &pc;
putchar(**ppc);
/* ==> ‘t’ */
Miguela Fernandes
52
Ponteiros para Ponteiros
Ponteiro para ponteiro para ponteiro...
Ex:
char *pc, **ppc, ***pppc;
Um ponteiro permite modificar o objeto apontado ou apontar
para outro objeto do mesmo tipo
Miguela Fernandes
53
Download

Ponteiros