Você está na página 1de 11

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos

s e Programao

4 Ponteiros
Ponteiro uma varivel que contm o endereo de memria de outra varivel. Da o seu nome, pois ele aponta para outra varivel. possvel ter um apontador para qualquer tipo de varivel

4.1 Declarando e Utilizando Ponteiros


Para declarar um ponteiro temos a seguinte forma geral: tipo_do_ponteiro *nome_da_varivel; o asterisco (*) que faz o compilador saber que aquela varivel no vai guardar um valor mas sim um endereo para aquele tipo especificado. Exemplos de declaraes: int *pt; //Declarao de um ponteiro para um inteiro char *temp,*pt2; //Declarao de ponteiros para caracteres Isto significa que eles apontam para um lugar indefinido. Este lugar pode estar, por exemplo, na poro da memria reservada ao sistema operacional do computador. Usar o ponteiro nestas circunstancias pode levar a um travamento do micro, ou a algo pior. Importante! Uma vez declarado, o ponteiro deve ser associado ao endereo da varivel desejada para que possa ser usado. Para atribuir um valor a um ponteiro recm-criado poderamos igual-lo a um valor de memria. Mas, como saber a posio na memria de uma varivel do nosso programa? Seria muito difcil saber o endereo de cada varivel que usamos, mesmo porque estes endereos so determinados pelo compilador na hora da compilao e realocados na execuo. Podemos ento deixar que o compilador faa este trabalho por ns. Para saber o endereo de uma varivel basta usar o operador &. Veja o exemplo: int count=10; // Declarao de uma varivel count com valor 10 int *pt; //Declarao de um ponteiro pt para um inteiro pt=&count; //armazena em pt o endereo de count Observao: operador & = fornece o "endereo de uma varivel" o operador * = fornece o "contedo de um objeto apontado por um apontador". Considere o seguinte cdigo: int x = 1, y = 2; int *ip; ip = &x; y = *ip; x = (int) ip; *ip = 3; Assuma que a varivel x se encontra armazenada na posio de memria 100, y na posio 200 e ip na posio 1000. Note-se que um apontador uma varivel como as outras e os valores armazenados neste ocupam posies na memria tambm. a natureza dos valores que se armazenam nos apontadores que novo. Veja-se a figura seguinte: As atribuies x=1 e y=2 obviamente colocam esses valores nas posies de memria das variveis x e y. ip declarado como sendo um apontador para um inteiro e a colocado o endereo da varivel x (&x). Assim ip fica com o valor 100.

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

A seguir, a varivel y fica com o valor da posio de memria cujo endereo se encontra em ip. No exemplo ip aponta para a posio de memria 100 - que o endereo de x. Assim y fica com o valor de x, que 1.
ip=&x; x 1 100 y=*ip; x x=ip; x 1 100 100 100 *ip=3; x 3 100 y y y y 2 200 1 200 2 200 2 200 ip ip ip ip 100 1000 100 1000 100 1000 100 1000

J vimos que o C permite converses de tipos. Assim possvel converter um apontador num inteiro (se tiverem os mesmo tamanhos - em geral 32 bits). O valor de ip na 3 instruo transferido para x. Finalmente transfere-se para o local apontado por ip o valor 3. Como ip contm o endereo de x para a que vai parar o valor 3. Aqui vo dois exemplos de usos simples de ponteiros:
#include <stdio.h> int main () { int num,valor; int *p; num=55; p=&num; /* Pega o endereco de num */ valor=*p; /* Valor e igualado a num de uma maneira indireta */ printf ("\n\n%d\n",valor); printf ("Endereco para onde o ponteiro aponta: %p\n",p); printf ("Valor da variavel apontada: %d\n",*p); return(0); } #include <stdio.h> int main () { int num,*p; num=55; p=&num; /* Pega o endereco de num */ printf ("\nValor inicial: %d\n",num); *p=100; /* Muda o valor de num de uma maneira indireta */ printf ("\nValor final: %d\n",num); return(0); }

Nos exemplos acima vemos um primeiro exemplo do funcionamento dos ponteiros. No primeiro exemplo, o cdigo %p usado na funo printf() indica funo que ela deve imprimir um endereo.

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

4.2 Operaes com Ponteiros


4.2.1 Igualdade entre Ponteiros
A primeira operao com ponteiros a igualdade entre dois ponteiros. Dados dois ponteiros p1 e p2 pode-se igual-los fazendo p1=p2. Desta forma, p1 passa a apontar para o mesmo endereo de memria que p2 aponta. Para que a varivel apontada por p1 tenha o mesmo contedo da varivel apontada por p2 deve-se fazer *p1=*p2. Basicamente, depois que se aprende a usar os dois operadores (& e *) fica fcil entender operaes com ponteiros.

4.2.2 Incremento e Decremento de Ponteiros


As prximas operaes, tambm muito usadas, so o incremento e o decremento. Quando se incrementa um ponteiro, ele passa a apontar para o prximo valor do mesmo tipo para o qual o ponteiro aponta. Isto , se temos um ponteiro para um inteiro e o incrementamos ele passa a apontar para o prximo inteiro. Esta mais uma razo pela qual o compilador precisa saber o tipo de um ponteiro: se voc incrementa um ponteiro char* ele anda 1 byte na memria e se voc incrementa um ponteiro double* ele anda 8 bytes na memria. O decremento funciona de forma semelhante. Supondo que p um ponteiro, as operaes so escritas como: p++; p--; Operaes com ponteiros so diferentes de operaes com o contedo das variveis para as quais os ponteiros apontam. Por exemplo, para incrementar o contedo da varivel apontada pelo ponteiro p, faz-se: (*p)++;

4.2.3 Soma e Subtrao de Inteiros com Ponteiros


Outras operaes aritmticas teis so a soma e subtrao de inteiros com ponteiros. Vamos supor que se queira incrementar um ponteiro de 15. Basta fazer: p=p+15; ou p+=15; E para usar o contedo do ponteiro 15 posies adiante, faa: *(p+15); A subtrao funciona da mesma maneira. Importante: H entretanto operaes que voc no pode efetuar num ponteiro. Voc no pode dividir ou multiplicar ponteiros, adicionar dois ponteiros, adicionar ou subtrair floats ou doubles de ponteiros.

4.2.4 Comparao entre Ponteiros


Uma outra operao, s vezes til, a comparao entre dois ponteiros. Para verificar se dois ponteiros so iguais ou diferentes usa-se: == e !=, respectivamente. No caso de operaes do tipo >, <, >= e <= est-se comparando os valores das posies de memria para as quais os ponteiros apontam. Ento uma comparao entre ponteiros pode nos dizer qual dos dois est "mais adiante" na memria. A comparao entre dois ponteiros se escreve como a comparao entre outras duas variveis quaisquer: p1>p2 Exerccios: 1) Explique a diferena entre a) p++; b) (*p)++; c) *(p++); 2) O que quer dizer *(p+10);? 3

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

3) Qual o valor de y no final do programa? Tente primeiro descobrir e depois verifique no computador o resultado. A seguir, escreva um /* comentrio */ em cada comando de atribuio explicando o que ele faz e o valor da varivel esquerda do '=' aps sua execuo. 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); } 4) Escreva um /* comentrio */ em cada comando de atribuio explicando o que ele faz e o valor da varivel esquerda do '=' aps sua execuo. #include <stdio.h> int main() { int *flp, *flq, x; x = 0; flp = &x; flq = &x; *flp = *flq + 10; printf ("*flq + 10 = %d\n", *flp); ++*flp; printf ("++*flp = %d\n", *flp); (*flq)++; printf ("(*flq)++ = %d\n", *flq); flq = flp; return(0); } 5) Simule a execuo do seguinte programa:
#include stdio.h main() { int i, k,*pi,*pk; char a; i = 2; k = 0; puts(Qual sera o valor de k? ); pk = &k; pi = &i; *pk = i; printf(para *pk = i, temos k= %d\n,k); k = *pi; printf(para k = *pi, temos k= %d\n,k); scanf(%c,&a); }

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

4.3 Ponteiros e Arrays


Considere a declarao de uma matriz da seguinte forma: tipo_da_varivel nome_da_varivel [tam1][tam2] ... [tamN]; o compilador C calcula o tamanho, em bytes, necessrio para armazenar esta matriz. Este tamanho : tam1 x tam2 x tam3 x ... x tamN x tamanho_do_tipo O compilador ento aloca este nmero de bytes em um espao livre de memria. O nome da varivel declarada um ponteiro para o tipo da varivel da matriz. Este conceito fundamental. Eis porque: Tendo alocado na memria o espao para a matriz, ele usa o nome da varivel (que um ponteiro) e aponta para o primeiro elemento da matriz. nome_da_varivel[ndice] *(nome_da_varivel+ndice) Agora podemos entender como que funciona um vetor! Vamos ver o que podemos tirar de informao deste fato. Fica claro, por exemplo, porque que, no C, a indexao comea com zero. porque, ao pegarmos o valor do primeiro elemento de um vetor, queremos, de fato, *nome_da_varivel e ento devemos ter um ndice igual a zero. Ento sabemos que: *nome_da_varivel equivalente a nome_da_varivel[0] Considere a seguinte declarao de array: int ar[] = {10, 50, 20, 30}; E o ponteiro: int *ptr; E a seguinte linha de cdigo ptr = &ar[0]; Quando esta for executada, ptr estar associado ao primeiro byte da array. Como ptr aponta para o incio da array (elemento 0), o endereamento indireto *ptr poder obter ou modificar o valor deste elemento. Para acessar os demais elementos - Considerando que ptr est apontando para o elemento 0, basta increment-lo de uma unidade para mov-lo para o elemento 1, ou seja, ptr++; ou ptr += 1; Assim, na aritmtica dos ponteiros, os compiladores ajustam os endereos de acordo com o tamanho dos elementos da array e o programador no precisa se preocupar com isto (Exemplo: se em vez de int os dados fossem do tipo float, o endereo seria incrementado de 4 bytes). Estando ptr apontado para o elemento 1, para retornar ao 0, basta fazer um decremento no ponteiro, ptr--; ou ptr -= 1; Em resumo pode-se dizer que a simples soma ou subtrao ao ponteiro permite o acesso a qualquer elemento do array. Entretanto, cabe a quem programa cuidar para que o ponteiro no ultrapasse os limites da array. Caso contrrio, o programa poder ficar corrompido, com resultados imprevisveis. Os compiladores, normalmente, no verificam isso. No incio deste tpico foi usada a seguinte linha para inicializar o ponteiro: ptr = &ar[0]; Mas poderia ser perfeitamente desta forma: ptr = ar; Isto significa que o nome de uma array , na realidade, um ponteiro e pode ser usado da mesma forma. Exemplo: Considere o seguinte cdigo de programa para zerar uma matriz de 50 elementos por 50 elementos: int main () { float matrx [50][50]; int i,j; 5

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

for (i=0;i<50;i++) for (j=0;j<50;j++) matrx[i][j]=0.0; return(0); } Usando ponteiros, pode-se reescrever o cdigo conforme demonstrado abaixo: int main () { float matrx [50][50]; float *p; int count; p=&matrx[0][0]; for (count=0;count<2500;count++) { *p=0.0; p++; } return(0); } No primeiro programa, cada vez que se faz matrx[i][j] o programa tem que calcular o deslocamento do ponteiro. Ou seja, o programa tem que calcular 2500 deslocamentos. No segundo programa o nico clculo que deve ser feito o de um incremento de ponteiro. Fazer 2500 incrementos em um ponteiro muito mais rpido que calcular 2500 deslocamentos completos. H uma diferena entre o nome de um vetor e um ponteiro que deve ser frisada: um ponteiro uma varivel, mas o nome de um vetor no uma varivel. Isto significa, que no se consegue alterar o endereo que apontado pelo "nome do vetor". Seja: int vetor[10]; int *ponteiro, i; ponteiro = &i; /* as operaes a seguir so invlidas */ vetor = vetor + 2; /* ERRADO: vetor no varivel */ vetor++; /* ERRADO: vetor no varivel */ vetor = ponteiro; /* ERRADO: vetor no varivel */ /* as operaes a seguir so vlidas */ ponteiro = vetor; /* CERTO: ponteiro varivel */ ponteiro = vetor+2; /* CERTO: ponteiro varivel */

4.4 Ponteiros e Strings


Desde que uma string uma array de elementos tipo char, as operaes com strings ocorrem conforme tpico anterior, mas aqui esto algumas notaes mais elegantes para simplificar a sintaxe. Seja, por exemplo o seguinte programa: #include <stdio.h> main(){ int i; char rua[] = "nova"; char *ptr = rua; for (i=0; i<4; i++) printf( "%d> %c\n", i, *ptr++ ); } 6 A sada seria: 0> n 1> o 2> v 3> a

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

Strings tm um caractere nulo aps o ltimo elemento. Assim uma verso mais elegante do programa seria: #include <stdio.h> main(){ int i = 0; char rua[] = "nova"; char *ptr = rua; while( *ptr ) printf( "%d> %c\n", i++, *ptr++ ); } Entretanto o loop while permite o seguinte artifcio: *ptr ir parar o loop quando chegar no caractere nulo no final da string. Agora uma outra verso do programa: #include <stdio.h> main(){ int i; char rua[] = "nova"; char *ptr = rua; for (i=0; i<4; i++) printf( "%d> %c\n", i, *(rua+i) ); } Diferena: no ltimo argumento de printf foi usado *(rua+i) em lugar de *ptr++. Isso porque, conforme tpico anterior, o nome de uma array tambm um ponteiro para a mesma e pode ser usado como tal. Tambm poderia usar o clssico rua[i]. As notaes *ptr++ (isto incrementado para cada i), *(rua+i) e rua[i] se equivalem e podem ser usadas sem distino. Entretanto, muitos programadores preferem a notao como ponteiro por ser mais rpida em certas condies. Mas no s isso. Depois de voc se habituar com os ponteiros e de fazer uso intensivo deles, voc ir certamente preferir a notao como ponteiro para dar uma aparncia mais homognea aos seus cdigos. Exerccios: 1) Inverter os elementos de uma string, usando ponteiros: Ex: Dada a string Hoje tem sol retornar los met ejoh. A sada seria a mesma do anterior.

2) Ler uma array de inteiros [5][1] e imprimir os elementos do array usando ponteiros. 3) Considere o seguinte trecho de programa: int a=5, b=6, c=7; int v[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90} int *pt1, *pt2, *pt3; pt1=&a; pt2=&b; pt3=&c; pt1=pt3; pt2=pt3; 7

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

*pt1 = *pt2 + *pt3; pt1 = &v[3]; for (int k=0; k<3; k++){ *pt1 = *pt1 + 1000; pt1 = pt1 + 2; } Qual o contedo final: a) Das variveis a, b e c? b) Do vetor v? 4) Considere o seguinte trecho de programa: int a=5, b=6, c=7; int v[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90} int *pt1, *pt2, *pt3; pt1=&a; pt2=&b; pt3=&c; pt2=pt1; *pt3 = *pt2 + 2000; pt1 = &v[8]; for (int k=0; k<2; k++){ *pt1 = *pt1 - 5; pt1 = pt1 - 3; } Qual o contedo final: a) Das variveis a, b e c? b) Do vetor v? 5) Considere o seguinte trecho de programa: int a=5, b=6, c=7; int v[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90} int *pt1, *pt2, *pt3; pt1=&a; pt2=&b; pt3=&c; pt1 = pt2; pt3 = pt2; 8

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

*pt2 = *pt3 + 1000; pt1 = v; pt1 = pt1 + 1; for (int k=0; k<2; k++){ *pt1 = *pt1/2; pt1 = pt1 + 4; } Qual o contedo final: a) Das variveis a, b e c? b) Do vetor v?

Exerccios de Reviso
1. Qual das instrues abaixo correta para declarar um ponteiro para inteiro? a) *int pti; b) *pti; c) &i; d) int_pti pti; e) int *pti; 2. Seja a seguinte seqncia de instrues em um programa C: int *pti; int i = 10; pti = &i; Qual afirmativa falsa? a) pti armazena o endereo de i b) *pti igual a 10 c) ao se executar *pti = 20; i passar a ter o valor 20 d) ao se alterar o valor de i, *pti ser modificado e) pti igual a 10 3. Seja a seguinte seqncia de instrues em um programa C: int *pti; int veti[]={10,7,2,6,3}; pti = veti; Qual afirmativa falsa? a) *pti igual a 10 b) *(pti+2) igual a 2 c) pti[4] igual a 3 d) pti[1] igual a 10 e) *(veti+3) igual a 6 4. Na seqncia de instrues abaixo: float f; float *pf; pf = &f; scanf("%f", pf); 9

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

a) b) c) d) e)

Efetuamos a leitura de f No efetuamos a leitura de f Temos um erro de sintaxe Deveramos estar usando &pf no scanf Nenhuma das opes anteriores

5. Verifique o programa abaixo. Encontre o seu erro e corrija-o para que escreva o numero 10 na tela. #include <stdio.h> int main() { int x, *p, **q; p = &x; q = &p; x = 10; printf("\n%d\n", &q); return(0); } 6. O que est errado com os programas abaixos? Descubra e indique a soluo para consert-los. Execute-o no computador para ver se o erro foi resolvido. a) void main() /* esse programa esta errado */ { int x, *p; x = 10; *p = x; } b) void main() /* esse programa esta errado */ { int x, *p; x = 10; p = x; printf ("%d", *p); } 7. Simule a execuo do programa abaixo: #include stdio.h main() { int i,k,*pi,*pk; char a; i = 2; k = 0; puts(Qual sera o valor de k? ); pk = &k; pi = &i; *pk = i; printf(para *pk = i, temos k= %d\n,k); k = *pi; printf(para k = *pi, temos k= %d\n,k); scanf(%c,&a); 10

Ministrio da Educao Universidade Federal de Santa Maria Centro de Tecnologia Curso de Engenharia Eltrica Disciplina ELC 1022 Algoritmos e Programao

} 8. Simule a execuo do programa abaixo: main() { int x,y,*px,*py; printf(Digite um valor: ); scanf(%d,&x); px = &x; y = *px; printf(digitou= %d e y= %d\n,x,y); *px = 8; printf(valor mudou para %d\n,x); } 9. Simule a execuo do programa a seguir: main() { char a,b,*p; b = c; p = &a; *p = b; printf(%c,a); } 10. Escreva uma declarao para armazenar os seguintes valores em um vetor chamado rates: 12.9, 18.6, 11.4, 9.5, 15.2, 17.6. inclua a declarao em um programa que indique os valores no vetor usando a notao do ponteiro. 11. Escreva um programa em C para ler uma string e um nmero n e eliminar os n caracteres do incio da string. A string resultante deve ser mostrada na tela. Por exemplo, lida a string programa e o nmero 3, deve mostrar na tela a palavra grama. 12. Escrever um programa em C que l um caractere e uma string de at 20 caracteres, e passe estes valores para uma funo que elimine as ocorrncias do caractere na string. A string deve ser recebida como um ponteiro, e manipulada sem o uso de ndices.

11

Você também pode gostar