530 likes | 641 Views
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.
E N D
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
Conceitos básicos • Exemplo int x= 10; • 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’ printf(“Endereço de z = %d ”, &z); // Endereço de x = 105 Miguela Fernandes
x z ptr 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 // Estou a atribuir o endereço de x a ptr Miguela Fernandes
Declarar Ponteiros • Sintaxe tipo_dado *nome_ponteiro; Exemplo: int x; int*ptr; /* compilador sabe que ptr é um ponteiro para inteiro */ *-O asterisco indica que é um ponteiro Exemplos char x, *p, y, * ap; //char * p ou char* p Float *p_num, num; Miguela Fernandes
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
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 Fernandes
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 = NULL Miguela Fernandes
Manipular Ponteiros x • 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 ptr Miguela Fernandes
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
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
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; /* OK */ p2 = &y; /* OK */ p1 = &z; /* Erro */ p2 = &x; /* Erro */ } Um apontador para o tipo xpty, avança sempre o sizeof(xpty) Miguela Fernandes
Cuidado com os tipos de dados c i f ptr_c ptr_i ptr_f Sizeof(char) ≠ Sizeof(int) ≠ Sizeof(float) Não posso fazer: ptr_c = &i; ptr_i=&f; Miguela Fernandes
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
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; /* neste caso ptr aponta para um inteiro */ ptr = &f; /* agora para um float */ Miguela Fernandes
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
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
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
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
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
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
Ponteiros e Vectores Exemplo 2 Programa que dá o numero de elementos de um vector antes de encontrar o 0. Miguela Fernandes
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
Aritmética de Ponteiros vect ptr 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
Aritmética de Ponteiros vect ptr printf(“%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 Fernandes
Aritmética de Ponteiros vect ptr printf(“%d”, ptr);//100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr);// 2 printf(“%d”, vect [1]); // 0 printf(“%d”, (*ptr)++); // 0 printf(“%d”, vect [1]); printf(“%d”, *(ptr++)); printf(“%d”, *(ptr+2)); printf(“%d”, ptr); Miguela Fernandes
Aritmética de Ponteiros vect ptr printf(“%d”, ptr);//100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr);// 2 printf(“%d”, vect [1]); // 0 printf(“%d”, (*ptr)++); // 0 printf(“%d”, vect [1]); // 1 printf(“%d”, *(ptr++)); printf(“%d”, *(ptr+2)); printf(“%d”, ptr); Miguela Fernandes
Aritmética de Ponteiros vect ptr printf(“%d”, ptr);//100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr);// 2 printf(“%d”, vect [1]); // 0 printf(“%d”, (*ptr)++); // 0 printf(“%d”, vect [1]); // 1 printf(“%d”, *(ptr++)); // 1 printf(“%d”, *(ptr+2)); printf(“%d”, ptr); Miguela Fernandes
Aritmética de Ponteiros vect ptr printf(“%d”, ptr);//100 printf(“%d”, *ptr); // 2 printf(“%d”, ++ptr);// 2 printf(“%d”, vect [1]); // 0 printf(“%d”, (*ptr)++); // 0 printf(“%d”, vect [1]); // 1 printf(“%d”, *(ptr++)); // 1 printf(“%d”, *(ptr+2)); // 5 printf(“%d”, ptr); // 104 Miguela Fernandes
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
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
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 Fernandes
Exemplo - variação voidmain () { 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
Exemplo - variação voidmain () { 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 Fernandes
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
Exercício 3 • Escreva um programa que imprima um vector de inteiros na ordem inversa endereçando os elementos com um ponteiro Miguela Fernandes
Cuidados... • C não controla os limites dos arrays, o programador deve fazê-lo • Ex: • encontrar o erro: voidmain () { 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
Cuidados... voidmain () { 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
Cuidados... • Um ponteiro deve sempre apontar para um local válido antes de ser utilizado • Ex: voidmain () { int i=10, *pi; *pi = i; /*erro ! pi nao tem endereco valido*/ } Miguela Fernandes
Ponteiros e Strings • strings são vectores de caracteres e podem ser acedidos através de char * voidmain () { 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
Ponteiros e Strings • operações sobre strings com ponteiros void StrCpy (char *destino, char *origem) { while (*origem) /* *origem==0 encerra while */ { *destino=*origem; origem++; destino++; } *destino='\0'; } origem a b c d e \0 a b destino Miguela Fernandes
Ponteiros e Strings • variação de strcpy: void strcpy (char *destino, char *origem) { while ((*destino = *origem) != ‘\0’) destino++, origem++; } Miguela Fernandes
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] [4,9] [1,9] [0,9] [0,0] Miguela Fernandes
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
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
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 staticchar 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
Conversão de Data • Organização lógica e física da tabela: Miguela Fernandes
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
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
J o a o \0 M a r i a \0 A n t o n i o \0 Z a c a r i a s \0 C a r l o s \0 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) Matriz (ma) Miguela Fernandes