Professional Documents
Culture Documents
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
Next: 29 Strings e Ponteiros Up: 2 Tpicos Avanados Previous: 27 Estruturas Subseces 28.1 28.2 28.3 28.4 28.5 28.6 28.7 O operador de endereo (&) Tipo ponteiro O operador de dereferncia: * Atribuies envolvendo ponteiros Aritmtica de ponteiros Ponteiros e Arrays Ponteiros e Estruturas 28.7.1 Acesso a membros de estrutura via ponteiro: O operador
->
28.8 Ponteiros como argumentos de funes 28.8.1 Arrays como argumentos de funes 28.8.2 Ponteiros para estruturas como argumentos de funes 28.9 Precedncia de operadores
28 Ponteiros
Em linguagem C a cada varivel est associado: (i) um nome; (ii) um tipo; (iii) um valor; e (iv) um endereo. Considere as seguintes denies de variveis.
int i = 5; char c = 'G';
A varivel inteira i est armazenada no endereo 1342. Ela usa dois bytes de memria (quando um objeto usa mais de um byte, seu endereo onde ele comea - neste
1 de 11
14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
caso, 1342 e no 1343). A varivel do tipo char c est armazenada no endereo 1346 e usa um byte de memria. O compilador que controla do local de armazenamento destas variveis em memria.
1342 1346
float).
verdade que todos os endereos tem o mesmo tamanho4, mas ns tambm precisamos saber algo sobre o que armazenado no endereo de memria apontado (quantos bytes ocupa e como os bytes devem ser interpretados). Assim, a declarao de um tipo ponteiro em C feita da seguinte forma:
tipo *nome_var;
Esta declarao indica que est sendo denido um ponteiro para tipo chamado nome_var. Por exemplo, um tipo ponteiro usado para apontar para inteiros chamado ponteiro para int e isso denotado por um int *. Variveis do tipo ponteiro para int so usadas para armazenar endereos de memria que contem valores do tipo int. Dadas as denies de i e ambos do tipo ponteiro.
int *pi; char *pc; c
pi
pc,
Nesta denio as variveis no foram inicializadas com nenhum valor. Podemos inicializ-las com:
pi = &i;
2 de 11
14-04-2013 20:17
28 Ponteiros
pc = &c;
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
Depois destas atribuies, o valor de Note que nesta denio da varivel (ponteiro para int).
pi
seria
1342,
e o valor de
pc
seria
1346. int *
int *pi, pi
o nome da varivel e
o tipo de
pi
Quando um ponteiro aponta para um endereo de memria, a operao para acessar o contedo do endereo apontado chamado de dereferncia. O operador unrio * usado para fazer a dereferncia. Note que este uso do smbolo * no tem relao com o smbolo de multiplicao. Usando os exemplos anteriores, *pi o objeto apontado por pi (no caso, o valor de um inteiro).
*pi *pc
5 'G'
Como um ponteiro dereferenciado (tais como *pi ou *pc) refere-se a um objeto na memria, ele pode ser usado no s como valor, mas tambm como um lvalue. Isto signica que um ponteiro dereferenciado pode ser usado no lado esquerdo de uma atribuio. Veja alguns exemplos:
printf("Valor= %d, Char = %c\n", *pi, *pc); *pi = *pi + 5; *pc = 'H';
no lado esquerdo do = refere-se ao endereo de memria para o qual pi aponta. *pi no lado direito do = refere-se ao valor armazenado no endereo apontado por pi. A sentena *pi = *pi + 5; faz com que o valor armazenado no endereo apontado por pi seja incrementado de 5. Note que o valor de *pi muda, no o valor de pi.
*pi
Os exemplos acima ilustram como uma varivel pode ser acessada diretamente (atravs do seu nome) ou indiretamente (atravs de um ponteiro apontando para o endereo da varivel).
3 de 11
14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
abaixo:
int *p1, *p2, x; float *p3; p1 = &x; p2 = p1; p3 = p1; /* Correto */ /* Correto */ /* Incorreto. Compilador acusa "Warning". */
No exemplo acima, a linguagem C admite a atribuio de um ponteiro para outro de outro tipo (p3 = p1;), mas a compilao acusa uma mensagem de aviso. Posteriormente sero vistas situaes em que a atribuio de ponteiros de tipos diferentes devem ocorrer e como devem ser manipuladas em C.
Um ltimo ponto a respeito de operaes sobre ponteiros: Adicionar um ponteiro a outro no produz nenhum resultado prtico ou vlido.
4 de 11
14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
pstr = nome; ptr = val; pstr = nome + 4; ptr = val + 5; pstr = nome++;
/* Equivalente a pstr = &nome[0] */ /* Equivalente a ptr = &val[0] */ /* Equivalente a pstr = &nome[4] */ /* Equivalente a ptr = &val[5] */ /* ATENCAO: INCORRETO !!! */ /* "nome" NO UM PONTEIRO */
Se um ponteiro aponta para um array, pode-se usar indistintamente as formas abaixo para acessar os elementos do array:
int val[10], x, *ptr; ptr = val; *(ptr + 3) = 7; ptr[3] = 10; /* Equivalente a ptr = &val[0] */ /* val[3] = 7 */ /* val[3] = 10 */ /* Equivalente a *(ptr + 3) = 10 */
/* ATENCAO:
val[7] = 20 */
5 de 11
14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
(*pfac).num = 32; /* o membro "num" da "struct facil" apontada por "pfac" */ (*pfac).ch = 'A'; /* o membro "char" da "struct facil" apontada por "pfac" */ }
Como se espera, quando se usa um ponteiro para um tipo struct, o ponteiro deve ter assinalado a si um valor ANTES de ser dereferenciado. A ordem pela qual um membro pode ser acessado atravs do ponteiro, the pointer : primeiro o ponteiro dereferenciado, e ento o operador de membro de estrutura e o nome do membro so usados para acessar um membro em particular da estrutura apontada pelo ponteiro. Uma vez que o operador . tem precedncia mais alta que o operador * (veja Tabela 6), os parenteses so necessrios.
->
Uma notao do tipo (*pfac).ch confusa, de forma que a linguagem C dene um operador adicional (->) para acessar membros de estruturas atravs de ponteiros. O operador -> formalmente usado como o operador ., exceto que ao invs do nome da varivel de estrutura, um ponteiro para o tipo struct usado esquerda do operador ->. No exemplo acima, as duas ltimas linhas de cdigo podem portanto ser reescritas como:
pfac->num = 32; pfac->ch = 'A'; /* o mesmo que (*pfac).num = 32; /* o mesmo que (*pfac).ch = 'A'; */ */ struct,
Basicamente, use o operador . se voc tem uma varivel de tipo caso voc tenha um ponteiro para um tipo struct.
e o operador
->
6 de 11
14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
printf("Voce entrou com %d e %d\n", a, b); /* Troca a e b */ troca(a, b); printf("Trocados, eles sao %d e %d\n", a, b); }
Quando a e b so passados como argumentos para troca(), na verdade, somente seus valores so passados. A funo no pode alterar os valores de a e b porque ela no conhece os endereos de a e b. Mas se ponteiros para a e b forem passados como argumentos ao invs de a e b, a funo troca() seria capaz de alterar seus valores; ela saberia ento em que endereo de memria escrever. Na verdade, a funo no sabe que os endereos de memria so associados com a e b, mas ela pode modicar o contedo destes endereos. Portanto, passando um ponteiro para uma varivel (ao invs do valor da varivel), habilitamos a funo a alterar o contedo destas variveis na funo chamadora. Uma vez que endereos de variveis so do tipo ponteiro, a lista de parmetros formais da funo deve reetir isso. A denio da funo troca() deveria ser alterada, e a lista de parmetros formais deve ter argumentos no do tipo int, mas ponteiros para int, ou seja, int *. Quando chamamos a funo troca(), ns no passamos como parmetros reais a e b, que so do tipo int, mas &a e &b, que so do tipo int *. Dentro da funo troca() dever haver mudanas tambm. Uma vez que agora os parmetros formais so ponteiros, o operador de dereferncia, *, deve ser usado para acessar os objetos. Assim, a funo troca() capaz de alterar os valores de a e b ``remotamente''. O programa abaixo a verso correta do problema enunciado para a funo
#include <stdio.h> void troca(int *, int *); /* function troca(px, py) * acao: troca os valores inteiros apontados por px e py * entrada: apontadores px e py * saida: valor de *px e *py trocados * suposicoes: px e py sao apontadores validos * algoritmo: primeiro guarda o primeiro valor em um temporario e troca */ void troca(int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; } main(void) { int a, b; printf("Entre dois numeros: "); troca():
7 de 11
14-04-2013 20:17
28 Ponteiros
scanf("%d %d", &a, &b);
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
printf("Voce entrou com %d e %d\n", a, b); /* Troca a e b -- passa enderecos */ troca(&a, &b); printf("Trocados, eles sao %d e %d\n", a, b); }
Basicamente, se a funo precisa alterar o valor de uma varivel na funo chamadora, ento passamos o endereo da varivel como parmetro real, e escrevemos a funo de acordo, ou seja, com um ponteiro como parmetro formal.
Observe no exemplo acima que a passagem dos arrays ao se chamar as funes func_1() e func_2() feita da mesma forma: Usa-se o NOME das variveis declaradas
8 de 11
14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
como arrays. Note tambm o uso dos argumentos formais nas funes: vet e ivet podem ser usadas como ponteiros ou como nomes de arrays (com a notao indexada por []).
Neste caso, main() passa para a funo obtem_endereco() um ponteiro para a variavel residencia. obtem_endereco() pode ento alterar o valor de residencia ``remotamente''. Este valor, em main(), ento passado para imprime_endereco(). Note-se que no necessrio
9 de 11 14-04-2013 20:17
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
passar um ponteiro para a estrutura se seu valor no ser mudado (como o caso da funo imprime_endereco()). De um modo geral, melhor passar ponteiros para estruturas ao invs de passar e retornar valores de estruturas. Embora as duas abordagens sejam equivalentes e funcionem, o programa ir apenas passar ponteiros ao invs de toda uma estrutura que pode ser particularmente grande, implicando em um tempo nal de processamento maior.
esquerda para direita (unrios) direita para esquerda esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita direita para esquerda esquerda para direita
Notas de rodap ... tamanho O operador sizeof() pode ser usado para determinar o tamanho de um ponteiro. Por exemplo, sizeof (char *)
10 de 11 14-04-2013 20:17
4
28 Ponteiros
http://www.inf.ufpr.br/nicolui/grad/ci067/Docs/NotasAula...
Next: 29 Strings e Ponteiros Up: 2 Tpicos Avanados Previous: 27 Estruturas Armando Luiz Nicolini Delgado 2011-02-03
11 de 11
14-04-2013 20:17