apontadores ou ponteiros t.l.p. 11º ano. miguela fernandes 2 conceitos básicos quando se define...
TRANSCRIPT
Apontadores ou Ponteiros
T.L.P. 11º Ano
Miguela FernandesMiguela Fernandes 22
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 FernandesMiguela Fernandes 33
Conceitos básicosExemplo int x= 10;
Não esquecer que ocupa 2 bytes. Então x está no endereço 102Não esquecer que ocupa 2 bytes. Então x está no endereço 102
O operador de endereço como já é vosso conhecido é 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); // printf(“Endereço de x = %d ”, &x); // Endereço de x = 102Endereço de x = 102
Exemplo char z =‘A’
printf(“Endereço de z = %d ”, &z); // printf(“Endereço de z = %d ”, &z); // Endereço de x = 105Endereço de x = 105
1 2
100 101 102 103 104 105
1 2 ‘A’
100 101 102 103 104 105
Miguela FernandesMiguela Fernandes 44
Apontadores/Ponteiros
x z ptr
1 2 ‘A’ 102
100 101 102 104 105
Os apontadores são variáveis que guardam os endereços de memória (&) de outras variáveis.
Então podemos fazer ptr = &x // Estou a atribuir o endereço de x a ptr
Miguela FernandesMiguela Fernandes 55
Declarar Ponteiros
Sintaxe
tipo_dado *nome_ponteiro;
Exemplo:intint x; x;
intint **ptr; /* compilador ptr; /* compilador sabesabe que ptr é um que ptr é um ponteiroponteiro para inteiro */ para inteiro */
**-- O asterisco indica que é um ponteiro
Exemplos
char x, *p, y, * ap; //char * p ou char* p
Float *p_num, num;
Miguela FernandesMiguela Fernandes 66
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 FernandesMiguela Fernandes 77
Iniciar Ponteiros
Já vimos que o operador “&” retorna endereço de uma variável
Para iniciar ponteiros temos que:int x = 10, *ptr; //Defino a var e o
ponteiro
ptr = &x; //Inicio o ponteiro
printf(“&x: %x ptr: %x”, &x, ptr);
&x: 0x03062fd8 ptr: 0x03062fd8
Miguela FernandesMiguela Fernandes 88
Iniciar Ponteiros c/ NULL
Para iniciar ponteiros temos que:
int x = 10, *ptr; //Defino a var e o ponteiro
ptr = &x; //Inicio o ponteiro
Quando não pretendo iniciar logo o ponteiro com valores tenho de:
ptr = NULLptr = NULL
Miguela FernandesMiguela Fernandes 99
Manipular Ponteiros
Imprimir o conteúdo de uma variável
int x = 10, *ptr = &x;
printf(“ x = %d”, x); // x = 10
Imprimir o conteúdo de um ponteiro
printf(“ ptr = %d”,ptr); // x = 102
Imprimir o valor para onde ele aponta
printf(“ x = %d”, *ptr); // x = 10
1 0
102
x
1 0 2
200
ptr
Miguela FernandesMiguela Fernandes 1010
Manipular Ponteiros
Se py e px são pointers para inteiros, então podemos fazer a seguinte declaração:
py=px; py=px; py fica a apontar p/ o mesmo que pxpy 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 FernandesMiguela Fernandes 1111
Exercício 11- 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;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 FernandesMiguela Fernandes 1212
Cuidado com os tipos de dadosOs ponteiros são variáveis tipadas:(int *) ≠ (float *) ≠ (char *)
void main() {
int *p1, x;
float *p2, y;
p1 = &x; /* OK */
p2 = &y; /* OK */
p1 = &z; /* Erro */
p2 = &x; /* Erro */
}
Um apontador para o tipo xpty, avança sempre o sizeof(xpty)
Miguela FernandesMiguela Fernandes 1313
Cuidado com os tipos de dados
c i f
100 102 107
140 141 142 143 144 145 146 147 148 149 150 151 152
‘A’ 1 2 3 . 1 4 1 5
100 101 102 103 104 105 106 107 108 109 110 111 112
ptr_c ptr_i ptr_fSizeof(char) ≠ Sizeof(int) ≠ Sizeof(float)
Não posso fazer: ptr_c = &i; ptr_i=&f;
Miguela FernandesMiguela Fernandes 1414
Exercício 2
Pratique a declaração e utilização de ponteiros. defina e inicialize uma variável inteiradefina e inicialize uma variável inteira defina um ponteiro para inteirodefina um ponteiro para inteiro modifique o valor da variável através do ponteiromodifique o valor da variável através do ponteiro verifique os novos valores da variável usando verifique os novos valores da variável usando printfprintf
Miguela FernandesMiguela Fernandes 1515
Ponteiros GenéricosUm 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; /* neste caso ptr aponta para um inteiro */
ptr = &f; /* agora para um float */
Miguela FernandesMiguela Fernandes 1616
Ponteiros GenéricosO tipo de dado apontado por um void pointer deve ser controlado pelo utilizador através do castSintaxe:
* (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 FernandesMiguela Fernandes 1717
Ponteiros e VectoresRelembrar:
O nome de um vector é um ponteiro (constante) para o 1º elemento do vector
Exemplo:
int v[10]; v == &v[0]int v[10]; v == &v[0]
Int *ptr;Int *ptr;
ptr= &v[0] // ou ptr =v;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 FernandesMiguela Fernandes 1818
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:floatfloat x[10], y[10]; x[10], y[10];floatfloat *ptr_f; *ptr_f;
x = y;x = y; /* NUNCA ERRO: x é constante ! */ /* NUNCA ERRO: x é constante ! */ ptr_f = x; /* SEMPRE OK */ptr_f = x; /* SEMPRE OK */
Miguela FernandesMiguela Fernandes 1919
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 FernandesMiguela Fernandes 2020
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 */
NotaO 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 FernandesMiguela Fernandes 2121
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 FernandesMiguela Fernandes 2222
Ponteiros e Vectores Exemplo 2
#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();
}
Programa que dá o numero de elementos de um vector antes de encontrar o 0.
Miguela FernandesMiguela Fernandes 2323
Aritmética de Ponteiros
É possível fazer operações aritméticas e relacionais entre ponteiros e inteiros
Soma ou subtracçãoint x[10], *ptr;int x[10], *ptr;
ptr[2] equivale a *(ptr+2)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 a frente
*(ptr - n) acede ao conteúdo de n elementos atrás*(ptr - n) acede ao conteúdo de n elementos atrás
ptr++ ptr++ acede ao próximo endereço elemento vector *acede ao próximo endereço elemento vector *
ptr-- acede ao endereço anterior do vector *ptr-- acede ao endereço anterior do vector *
* Não esquecer que avança o tamanho do tipo int 2 bytes, float 4 * Não esquecer que avança o tamanho do tipo int 2 bytes, float 4 bytes, etc.bytes, etc.
Miguela FernandesMiguela Fernandes 2424
Aritmética de Ponteirosvect
100
140 141 142 143 144 145 146 147 148 149 150 151 152
2 0 1 3 5 .. .. .. .. .. .. .. ..100 102 104 106 108 110 112 114 … ……
ptrQuais os seguintes resultados: ptr_10printf(“%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 FernandesMiguela Fernandes 2525
Aritmética de Ponteirosvect
100
140 141 142 143 144 145 146 147 148 149 150 151 152
2 0 1 3 5 .. .. .. .. .. .. .. ..100 102 104 106 108 110 112 114 … ……
ptrprintf(“%d”, ptr); //100 printf(“%d”, *ptr); // 2 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 FernandesMiguela Fernandes 2626
Aritmética de Ponteirosvect
102
140 141 142 143 144 145 146 147 148 149 150 151 152
2 0 1 3 5 .. .. .. .. .. .. .. ..100 102 104 106 108 110 112 114 … ……
ptrprintf(“%d”, ptr); //100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr); // 2
printf(“%d”, vect [1]); // 0printf(“%d”, (*ptr)++); // 0printf(“%d”, vect [1]);printf(“%d”, *(ptr++)); printf(“%d”, *(ptr+2));printf(“%d”, ptr);
Miguela FernandesMiguela Fernandes 2727
Aritmética de Ponteirosvect
102
140 141 142 143 144 145 146 147 148 149 150 151 152
2 1 1 3 5 .. .. .. .. .. .. .. ..100 102 104 106 108 110 112 114 … ……
ptrprintf(“%d”, ptr); //100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr); // 2
printf(“%d”, vect [1]); // 0printf(“%d”, (*ptr)++); // 0printf(“%d”, vect [1]); // 1printf(“%d”, *(ptr++)); printf(“%d”, *(ptr+2));printf(“%d”, ptr);
Miguela FernandesMiguela Fernandes 2828
Aritmética de Ponteirosvect
104
140 141 142 143 144 145 146 147 148 149 150 151 152
2 1 1 3 5 .. .. .. .. .. .. .. ..100 102 104 106 108 110 112 114 … ……
ptrprintf(“%d”, ptr); //100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr); // 2
printf(“%d”, vect [1]); // 0printf(“%d”, (*ptr)++); // 0printf(“%d”, vect [1]); // 1printf(“%d”, *(ptr++)); // 1 printf(“%d”, *(ptr+2)); printf(“%d”, ptr);
Miguela FernandesMiguela Fernandes 2929
Aritmética de Ponteirosvect
104
140 141 142 143 144 145 146 147 148 149 150 151 152
2 1 1 3 5 .. .. .. .. .. .. .. ..100 102 104 106 108 110 112 114 … ……
ptrprintf(“%d”, ptr); //100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr); // 2
printf(“%d”, vect [1]); // 0printf(“%d”, (*ptr)++); // 0printf(“%d”, vect [1]); // 1printf(“%d”, *(ptr++)); // 1 printf(“%d”, *(ptr+2)); // 5printf(“%d”, ptr); // 104
Miguela FernandesMiguela Fernandes 3030
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 FernandesMiguela Fernandes 3131
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 FernandesMiguela Fernandes 3232
Exemplo
void main ()
{
int arint[] = { 1,2,3,4,5,6,7 };
int size = 7;/* tamanho do array */
int i, *pi;
for (pi=arint, i=0; i < size; i++, pi++)
printf(“ %d “, *pi);
}
==> 1 2 3 4 5 6 7
Miguela FernandesMiguela Fernandes 3333
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 FernandesMiguela Fernandes 3434
Exemplo - variação
void main ()
{
int arint[] = { 1,2,3,4,5,6,7 };
int size = 7;/* tamanho do array */
int i, *pi;
for (pi=arint, i=0; i < size; i++)
printf(“ %d “, *pi++);
}
==> 1 2 3 4 5 6 7
Miguela FernandesMiguela Fernandes 3535
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 FernandesMiguela Fernandes 3636
Exercício 3
Escreva um programa que imprima um vector de inteiros na ordem inversa endereçando os elementos com um ponteiro
Miguela FernandesMiguela Fernandes 3737
Cuidados...
C não controla os limites dos arrays, o programador deve fazê-lo
Ex: encontrar o erro: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 FernandesMiguela Fernandes 3838
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 FernandesMiguela Fernandes 3939
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 FernandesMiguela Fernandes 4040
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==> abcdef
o incremento de pc o posiciona sobre o próximo caracter (byte a byte)
Miguela FernandesMiguela Fernandes 4141
Ponteiros e Strings
operações sobre strings com ponteirosvoid StrCpy (char *destino, char *origem)
{
while (*origem) /* *origem==0 encerra while */
{
*destino=*origem;
origem++;
destino++;
}
*destino='\0';
}
a b c d e \0
a b
origem
destino
Miguela FernandesMiguela Fernandes 4242
Ponteiros e Strings
variação de strcpy:
void strcpy (char *destino, char *origem)
{
while ((*destino = *origem) != ‘\0’)
destino++, origem++;
}
Miguela FernandesMiguela Fernandes 4343
Arrays Multidimensionais
Arrays podem ter diversas dimensões, cada uma identificada por um par de colchetes na declaração
Ex: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] [4,9][0,9] [1,9]
[0,0]
[4,9]
Miguela FernandesMiguela Fernandes 4444
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 FernandesMiguela Fernandes 4545
Array de CaracteresPercorrendo 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 FernandesMiguela Fernandes 4646
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 FernandesMiguela Fernandes 4747
Conversão de Data
Organização lógica e física da tabela:
tabela_dias
memória
0 31 31 31 31 31 31 3130 30 30 3028
0 31 31 31 31 31 31 3130 30 30 3029
0 31 3128 0 31 3128... ... 31 3130
Miguela FernandesMiguela Fernandes 4848
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 FernandesMiguela Fernandes 4949
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 FernandesMiguela Fernandes 5050
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”};
“Joao”
“Maria”
“Antonio”
“Zacarias”
“Carlos”
Ponteiros (as)
J o a oM a r i aA n t o n i oZ a c a r i a sC a r l o s
\0
\0\0
\0\0
Matriz (ma)
Miguela FernandesMiguela Fernandes 5151
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 FernandesMiguela Fernandes 5252
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 FernandesMiguela Fernandes 5353
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