Linguaguem de Programação II Aula 5 Ponteiros Prof. Luiz José Hoffmann Filho [email protected] Ponteiros • O que são ponteiros? o Um ponteiro é uma variável que contém um endereço de memória. Esse endereço é normalmente a posição de uma outra variável na memória. Se uma variável contém o endereço de uma outra, então a primeira variável é dita para apontar para a segunda. Ponteiros Endereço na memória Variável na memória 1000 1003 1001 1002 1003 1004 1005 JOSE Ponteiros • Declaração: o <tipo> *<nome da variável>; • Exemplo: o int *valor; o char *nome; Ponteiros • Os operadores de Ponteiros: o & - é um operador unário que devolve o endereço na memória do seu operando. o Exemplo: • m = &count; o * - é o complemento de &. É um operador unário que devolve o valor da variável localizada no endereço que o segue. o Exemplo: • q = *m; Ponteiros • Atribuição de ponteiros: #include <stdio.h> int main() { int x; int *p1, *p2; x = 1000; p1 = &x; p2 = p1; printf("%p \n", p2); /*escreve o endereço de x, não seu valor*/ printf("%d \n", *p2); /* escreve o valor de x */ return 0; } Ponteiros • Aritmética de ponteiros: o o o o o int *p1; p1 = &x; /* supondo que a posição de x é igual a 2000 */ p1++; /* incrementando em uma posição, agora vale 2001*/ P1--; /* decrementando em uma posição, agora vale 2000*/ P1 = p1 +10; /* Soma de posições, agora vale 2010*/ • Comparação de ponteiros: o If (p<q) o printf(“p aponta para uma memória mais baixa que q”); o If (p == q) o printf(“p aponta para a memória mesma que q”); Exercícios • Explique a diferença entre: o o o p++; (*p)++; *(p++); • O que quer dizer *(p+10);? • Explique o que você entendeu da comparação entre ponteiros. Exercícios • Qual o valor de y no final do programa? Tente primeiro descobrir e depois verifique no computaadore o resultado. A seguir, escreva um /*comentário */ em cada comando de atribuição explicando o que ele faz e o valor da variável à esquerda do ‘=’ após sua execução. int main() { int y, *p, x; y=0; p = &y; x = *p; x = 4; (*p)++; x--; (*p) += x; printf(“y = %d \n”, y); return(0); } Ponteiros • Ponteiros e Matrizes: char str[80], *p1; p1 = str; o p1 foi inicializado com o endereço de primeiro elemento da matriz str. o Para acessar o quinto elemento de str: str[4]; *(p1+4); • Vetor/Matriz de Ponteiros: int *x[10]; x[2] = &var; o Atribuir o endereço a variável var a uma posição do vetor *x[2]; o Valor de var. Ponteiros – Vetores/Matriz • Programa para zerar uma matriz: int main() { float matrx[50][50]; int i, j; for (i=0; i<50; i++) { for(j=0;j<50; j++) { matrx[i][j] =0.0; } } return(0); } Agora faça utilizando ponteiros? Ponteiros – Vetores/Matriz Programa para zerar um matriz usando ponteiros: int main() { float matrx[50][50]; int i; float *p; p = matrx[0]; for (i=0; i<2500; i++) { *p=0.0; p++; } return(0); } Ponteiros – vetor/matriz • Existe uma diferença entre o nome de um vetor e um ponteiro que deve ser frisada: um ponteiro é uma variável , mas o nome de um vetor não é uma variável. Isto significa que não se consegue alterar o endereço que é apontando pelo “nome do vetor”. int vetor[10]; int *p, i; p = &i; /* operações invalidas */ vetor = vetor + 2; vetor++; vetor = ponteiro; /* operações validas */ ponteiro = vetor; ponteiro = vetor + 2; • Ponteiros – Strings Seguindo o raciocínio, nomes de strings, são do tipo char*. Isto nos permite escrever a nossa função StrCpy(), que funcionará de forma semelhante à função strcpy() da biblioteca: #include <stdio.h> #include <stdlib.h> void StrCpy(char *destino, char *origem) { while(*origem) { *destino = *origem; origem++; destino++; } *destino = '\0'; } int main() { char str1[100], str2[100], str3[100]; printf("Entre com um string: "); scanf("%s", str1); StrCpy(str2, str1); StrCpy(str3, "Voce digitou a String "); printf("\n\n %s%s", str3, str2); return (0); } Ponteiros • Vetor de ponteiros: o int *pmatrx[10]; É um vetor que armazena 10 ponteiros para inteiros. Exercícios – Ponteiros + vetores • Fizemos a função StrCpy(). Faça a função StrLen() e StrCat() que funcionem como a função strlen() e strcat() de string.h respectivamente. Ponteiros • Indireção mútipla: int main() { int x, *p, **q; x = 10; p = &x; q = &p; printf(“%d”, **q); return 0; } • Inicialização de ponteiros: o int *p = NULL; o char *p = “alo mundo”; Exercício – Intereção múltiplas • Verifique o programa abaixo. Encontre o seu erro e corrija-o para que escreva o número 10 na tela. int main() { int x, *p, **q; p = &x; q = &p; X = 10; printf(“%d”, &q); return 0; } Inicialização de ponteiros • Grande problema, quando não inicializamos um ponteiro, ele provavelmente irá apontar para “lixo”; • Sempre inicializar um ponteiro com “NULL” ou algum valor válido. Inicialização de ponteiros #include <stdio.h> #include <string.h> int main() { char *p = "Alo mundo"; int i; printf("%s\n", p); for (i = strlen(p) -1; i > -1;i--) { printf( "%c ", p[i]); } printf("\n"); return; } Ponteiros • Alocação dinâmica: stdlib.h o Malloc = aloca memória int *p; If (!(p=malloc(50*sizeof(int)) { Printf(“sem memória.\n”); Return 0; } o Free = desaloca memória free(p); Ponteiros – Alocação de matriz #include <stdio.h> #include <string.h> int main() { char *s; int t; s = malloc(80); if (!s) return 0; scanf("%s",s); for ( t = strlen(s) - 1; t >= 0; t--) printf("%c", s[t]); free(s); return 0; } Exemplo Como exemplo de uso destas funções return 1; considere o problema de reservar n } posições para armazenar variáveis do /* A PARTIR DE AGORA VOLTAMOS tipo int. Para isto usamos o trecho de PARA VETORES COMUNS */ programa mostrado em 5. Observe que /* aqui uso pvetor , vamos ler um após alocar o espaço foi usada a vetor */ notação de vetores comuns. for (i = 0; i < n ; i ++) { #include < stdlib .h > scanf ( " % d " , &pvetor[ i ]); #include < stdio .h > } int main (void) /* faco alguma coisa */ { media = 0.0; int i , n , * pvetor ; for (i = 0; i < n ; i ++) { float media ; media += pvetor [ i ]; /* Define um valor para n , scanf ou n } = */ printf ( " % f \ n " , media ); scanf ( " % d " , & n ); /* aqui nao preciso mais de pvetor */ /* aloca espaco na memoria */ free ( pvetor ); pvetor = (int *) malloc ( n * s i z e o f(int)); return 0; i f (! pvetor ) { } puts ( " Sem memória . " ); Problemas com ponteiros 1 int main () { int x, *p; x = 10; *p = x; } Ele atribui o valor 10 a alguma posição de memória desconhecida. O ponteio p nunca recebeu um valor. Como seria a forma correta? p = &x; Problemas com ponteiros 2 int main () { int x, *p; x = 10; p = x; printf(“%d\n”, *p); } • Printf não imprime o valor de x, que é 10, na tela. Imprimi algum valor desconhecido por que a atribuição “p = x” esta incorreta. • A forma correta é: “p = &x” Problema com ponteiros 3 char s[80], y[80]; char *p1, *p2; p1 = s; p2 = y; If (p1<p2) …. Problema fazer uma “suposição” que os vetores são contiguos. Fazer comparação entre ponteiros que não apontam para um objeto comum produz resultados inesperados. Problema com ponteiros 4 int first[10], second[10]; int *p, t; p = first; for(t=0;t<20; t++) *p++ =t; Achar que dois vetores diferentes são adjacentes na memória. Problema com ponteiros 5 int main() { char *p1, s[80]; p1 = s; do { gets(s); while(*p1) printf(“ %d”,*p1++); } while (strcmp(s, “done”)); return; } Qual o problema aqui? Como posso resolver este problema? Problema com ponteiros 5 int main() { char *p1, s[80]; do { p1 = s; gets(s); while(*p1) printf(“ %d”,*p1++); } while (strcmp(s, “done”)); return; } Exercícios • Escreva um programa que declare uma matriz 100x100 de inteiros. Você deve inicializar a matriz com zeros usando ponteiros para endereçar seus elementos. Preencha depois a matriz com os números de 1 a 10000, também usando ponteiros. Bibliografia • Schildt, Herbet. C Completo e Total, 3ª ed. São Paulo. Markron Books, 1996.