Você está na página 1de 39

PONTEIROS

Prof Ms. Eng Elaine Ceclia Gatto Curso de Bacharelado em Engenharia de Computao Universidade do Sagrado CoraO USC Bauru/SP

Introduo
Ponteiros esto entre as capacidades mais difcieis de se dominar na linguagem C; Ponteiros permitem: Simular uma chamada por referncia; Criar e manipular estruturas dinmicas de dados; Estruturas de dados podem crescer e encolher no tempo de execuo; Listas interligadas, filas, pilhas, rvores, etc., so exemplos de estruturas de dados dinmicas; Ponteiros so variveis cujos valores so endereos de memria; Uma varivel comum contm claramente um valor especfico;

Introduo
Ponteiros so utilizados em situaes em que o uso do nome de uma varivel no permitido ou indesejvel; Ponteiros fornecem maneiras com as quais as funes podem realmente modificar os argumentos que recebem passagem por referncia; Ponteiros passam matrizes e strings mais convenientemente de uma funo para outra; Ponteiros manipulam os elementos de matrizes mais facilmente, por meio da movimentao de ponteiros para elas ou parte delas no lugar de ndices entre colchetes;

Introduo
Ponteiros alocam e desalocam memria dinamicamente no sistema; Ponteiros passam para uma funo o endereo de outra funo. Um ponteiro um tipo especial de varivel que foi concebida para conter o endereo de outra varivel; Um ponteiro armazena um endereo de memria, que a localizao de outra varivel; Uma varivel aponta para outra varivel quando a primeira contm o endereo da segunda;

Introduo
A memria do computador dividida em bytes, numerados de zero at o limite da memria do computador; Esses nmeros so chamados de endereos de bytes; Um endereo uma referencia que o computador usa para localizar variveis; Seu endereo o do primeiro byte ocupado por ela; Os programas, quando carregados, ocupam uma certa parte da memria; Toda varivel e toda funo dos programas em C comeam em um endereo particular, que chamado endereo da varivel ou da funo;

Introduo
Um ponteiro, diferentemente de uma varivel comum, contm um endereo de uma varivel que contm um valor especfico; Uma varivel comum referencia um valor diretamente; Um ponteiro referencia um valor indiretamente; INDIREO: a referncia de valor por meio de um ponteiro; Ponteiros devem ser definidos antes de sua utilizao, como qualquer outra varivel; Exemplo: int *countPtr, count; O que faz esse linha de cdigo? Pense!

Introduo
A linha acima pode ser reescrita da seguinte forma: int *countPrt; int count; Note que foram criadas duas variveis do tipo INT, entretanto, uma delas um ponteiro; Todo ponteiro necessita do smbolo * antes do nome da varivel; Portanto, int *countPtr especifica que a varivel countPtr do tipo int * - um ponteiro para um inteiro, e pode ser lido de duas formas: countPtr um ponteiro para int; countPtr aponta para um objeto do tipo int;

Introduo
A varivel count definida para ser um inteiro, e no um ponteiro para int; Se quisermos que count seja um ponteiro, devemos alterar a declarao int count para int *count;
count 7 countPtr count 7

count referencia diretamente uma varivel que contm o valor 7

countPtr referencia indiretamente uma varivel que contm o valor 7

Introduo
Cuidado: A notao *, usada para declarar variveis de ponteiro, no distribui para todos os nomes de variveis em uma declarao; Cada ponteiro precisa ser declarado com o * prefixado ao nome; Exemplo: se voc quiser declarar xPtr e yPtr como ponteiros int, ento use int *xPtr, *yPtr; Dica; Inclua as letras Ptr nos nomes de variveis de ponteiros para deixar claro que essas variveis so ponteiros, e, portanto, precisam ser tratadas de modo apropriado; Inicialize os ponteiros para evitar resultados inesperados;

Introduo
Ponteiros devem ser inicializados quando so definidios ou ento em uma instruo de atribuio; Ponteiros podem ser inicializados com NULL, zero, ou um endereo; NULL: no aponta para nada, uma constante simblica; Inicilizar um ponteiro com zero o mesmo que inicializar com NULL; Nesse caso zero convertido em um ponteiro apropriado; Zero o nico valor inteiro que pode ser atribud diretamente a um ponteiro. int *xPtr = NULL; int *yPtr = 0;

Introduo
Exemplo: para conhecer o endereo ocupado por uma varivel usamos o operador de endereos &. O resultado da operao um ponteiro constante. #include <stdio.h> #include <stdlib.h> int main(){ int i, j, k; printf(Endereo de i = %p \n, &i); printf(Endereo de j = %p \n, &j); printf(Endereo de k = %p \n, &k); system(Pause); return 0; }

Operadores de Ponteiros
& = operador de endereo = um operador unrio que retorna o endereo de seu operando; Exemplo: int y = 5; int *yPtr; yPtr = &y A terceira instruo atribui o endereo da varivel y varivel de ponteiro yPtr; A varivel yPtr aponta para y;

Operadores de Ponteiros
yPtr y 5

Representao grfica de um ponteiro apontando para uma varivel inteira na memria


Suponha que a varivel y esteja armazenada no local 60.000 da memria; Suponha que a varivel yPtr esteja armazenada no local 50.000 da memria; O operando do operador de endereo precisa ser uma varivel; O operador de endereo no pode ser aplicado a constantes, expresses ou variveis declaradas da classe register. yPtr Local na memria da varivel yPtr: 50.000 y 5 Local na memria da varivel y: 60.000

60.000

Representao grfica de y e yPtr na memria

Operadores de Ponteiros
O operador unrio *, retorna o valor do objeto apontado por seu operando; O operardor indireto * unrio e opera sobre um endereo ou ponteiro; O resultado da operao o nome da varivel localizada nesse endereo apontada; O nome da varivel representa o seu valor ou contedo; Por fim, resulta o valor da varivel apontada; Exemplo: printf(%d, *yPtr); Imprime o valor da varivel y; O uso de * chamado de desreferenciao de um ponteiro;

Operadores de Ponteiros
O operador de endereos & opera sobre o nome de uma varivel e resulta o seu endereo, j o operador indireto * opera sobre o endereo de uma varivel e resulta o seu nome. Dica: Acessar um contedo com um ponteiro que no foi devidamente inicializado ou que no foi designado para apontar um local especfico na memria um erro. Isso poderia causar um erro fatal no temp de execuo, ou poderia acidentalmente modificar dados e permitir que o programa fosse executado at o fim com resultados incorretos;

Operadores de Ponteiros
Exemplo: o cdigo a seguir demonstra a utilizao dos operadores & e *. %p mostra o local da memria como um inteiro hexadecimal na maioria das plataformas. #include <stdio.h> #include <stdlib.h> int main(){ int a; int *aPtr; a = 7; aPtr = &a; printf("Endereco de a = %p \n", &a); printf("O valor de aPtr = %p \n", aPtr); printf("O valor de a = %d \n", a); printf("O valor de aPtr = %d \n", *aPtr); printf("* e & sao complementos um do outro: \n"); printf("&*aPtr = %p \n", &*aPtr); printf("*&aPtr = %p \n", *&aPtr); system("Pause"); return 0; }

Operadores de Ponteiros
aPtr

#include <stdio.h> 0022FF44 0022FF44 7 #include <stdlib.h> int main(){ Nesta parte do programa, as variveis esto sendo int a; declaradas e inicializadas. A varivel a do tipo int int *aPtr; recebe o valor 7. O ponteiro para um inteiro, aPtr, a = 7; recebe o endereo da varivel a, que do tipo int. aPtr = &a; printf("Endereco de a = %p \n", &a); printf("O valor de aPtr = %p \n", aPtr); printf("O valor de a = %d \n", a); printf("O valor de aPtr = %d \n", *aPtr); printf("* e & sao complementos um do outro: \n"); printf("&*aPtr = %p \n", &*aPtr); printf("*&aPtr = %p \n", *&aPtr); system("Pause"); return 0; }

Operadores de Ponteiros
aPtr a

#include <stdio.h> 0022FF44 0022FF45 7 #include <stdlib.h> int main(){ int a; int *aPtr; Imprimindo o local da memria da a = 7; varivel int a como um inteiro aPtr = &a; hexadecimal. Observe que o valor do printf("Endereco de a = %p \n", &a); ponteiro aPtr o endereo da varivel printf(Valor de aPtr = %p \n", aPtr); int a. printf(Valor de a = %d \n", a); printf(Valor de aPtr = %d \n", *aPtr); printf("* e & sao complementos um do outro: \n"); printf("&*aPtr = %p \n", &*aPtr); printf("*&aPtr = %p \n", *&aPtr); system("Pause"); return 0; }

Operadores de Ponteiros
aPtr a

#include <stdio.h> 0022FF44 0022FF45 7 #include <stdlib.h> int main(){ int a; int *aPtr; Imprimindo os valores da varivel int a e a = 7; do ponteiro para um inteiro aPtr. Observe aPtr = &a; que aqui utiliza-se %d e no %p. Note printf("Endereco de a = %p \n", &a); que aqui estamos usando *aPtr e no printf(Valor de aPtr = %p \n", aPtr); apenas aPtr. Tambm na varivel a, usaprintf(Valor de a = %d \n", a); se apenas a e no &a. printf(Valor de aPtr = %d \n", *aPtr); printf("* e & sao complementos um do outro: \n"); printf("&*aPtr = %p \n", &*aPtr); printf("*&aPtr = %p \n", *&aPtr); system("Pause"); return 0; }

Operadores de Ponteiros
aPtr a

#include <stdio.h> 0022FF44 0022FF44 7 #include <stdlib.h> int main(){ int a; int *aPtr; a = 7; aPtr = &a; printf("Endereco de a = %p \n", &a); printf(Valor de aPtr = %p \n", aPtr); printf(Valor de a = %d \n", a); printf(Valor de aPtr = %d \n", *aPtr); printf("* e & sao complementos um do outro: \n"); printf("&*aPtr = %p \n", &*aPtr); Quando os dois operadores so printf("*&aPtr = %p \n", *&aPtr); aplicados consecutivamente varivel aPtr em qualquer system("Pause"); ordem,ento os operadores & e * return 0; so complementos um do outro }

Recapitulando: precedncia de operadores


Operadores ()[] + - ++ -- ! * & */% +< <= > >= == != && || Associatividade Esquerda para direita Direita para esquerda Esquerda para direita Esquerda para direita Esquerda para direita Esquerda para direita Esquerda para direita Esquerda para direita Tipo Mais alta Unrio Multiplicativo Aditivo Relacional Igualdade And lgico Or lgico

?: = += -= *= /= %=
,

Direita para esquerda Direita para esquerda


Esquerda para direita

Condicional Atribuio
Vrgula

Operaes com ponteiros


C permite operaes bsicas com ponteiros; Ponteiros so operandos vlidos em expresses aritmticas, atribuo e comparao; Nem todos os operadores normalmente usados nessas expresses so vlidos em conjunto com variveis de ponteiro; Um conjunto limitado de operaes aritmticas pode ser realizado com ponteiros; Um ponteiro pode ser incrementado ou decrementado; Um inteiro pode ser somado/subtrado a um ponteiro; Um ponteiro pode ser subtrado de outro ponteiro;

Operaes com ponteiros


#include <stdio.h> #include <stdlib.h> int main(){ //declaraes unsigned int x=5, y=6; unsigned int *px, *py; //atribuies px = &x; py = &y;
printf("\n Comparacoes "); if(px<py){ printf("py-px = %u \n", (px-py)); //subtraindo } else{ printf("px-py = %u \n", (py-px)); //subtraindo }

Operaes com ponteiros


printf("\n px = %p \n", px); printf("*px = %u \n", *px); //operador indireto printf("&px = %p \n", &px); //operador de endereos printf("\n py = %p \n", py); py++; //incrementando py printf("\n Apos incrementar py: \n "); printf("\n py = %p \n", py); printf("*py = %u \n", *py); //operador indireto printf("&py = %p \n", &py); //operador de endereos

printf("*py = %u \n", *py); //operador indireto


printf("&py = %p \n", &py); //operador de endereos

Operaes com ponteiros


px=py+5; //somando inteiros printf("\n Apos somar py+5 \n "); printf("\n px = %p \n", px); printf("*px = %u \n", *px); //operador indireto printf("&px = %p \n", &px); //operador de endereos

printf("\n px-py = %u \n \n", (px-py)); system("Pause"); return 0; }

Operaes com ponteiros

Operaes com ponteiros


Exemplo de soma:

int a[5]; aPtr = v; aPtr = &a[0]; aPtr += 2; Suponho que o primeiro elemento esteja no local 3000 e que o inteiro esteja armazenado em 4 bytes da memria, o resultado de aPtr+=2 ser 3008 pois (3000 + 2 * 4) = 3008. Se o inteiro estiver armazenado em 2 bytes da memria, ento o resultado ser 3004, pois (3000 + 2 * 2) = 3004.

Operaes com ponteiros


Ilustrando:
Local na memria 3000 3004 3008 3012 3016 Antes da soma

a[0] a[1] a[2] a[3] a[4]

Varivel de ponteiro aPtr

Local na memria

3000 3004 3008 3012 3016

a[0] a[1] a[2] a[3] a[4]

Varivel de ponteiro aPtr

Aps a soma

Operaes com ponteiros


Se um ponteiro estiver sendo incrementado ou decrementado em um, os operadores de incremento e decremento podero ser usados. As instrues abaixo incrementam e decrementam o ponteiro para que ele aponte para o prximo local ou para o local anterior. No caso do vetor, aponta para o prximo elemento ou elemento anterior. ++aPtr; aPtr++; --aPtr; aPtr--;

Operaes com ponteiros


Suponha que aPtr tem o local 3000 e a2Ptr tem o local 3008, ento: x = a2Ptr aPtr; Faz com que x receba o nmero de elementos do vetor aPtr para a2Ptr, resultado = 2 (duas posies). Aritmtica de ponteiros s funciona com ARRAYS (matrizes e vetores); A menos que as variveis de mesmo tipo sejam elementnos adjacentes de um array, elas no sero armazenadas em posies contguas na memria (uma aps a outra)

Operaes com ponteiros


Cuidado: Usar aritmtica de ponteiro em um ponteiro que no se aplique a um elemento em um array causa um erro; Subtrair ou comparar dois ponteiros que no se referem a elementos do mesmo array causa tambm um erro; Ultrapassar o final de um array ao usar a aritmtica de ponteiro tambm causa um erro; Dica: A maioria dos computadores de hoje tem inteiros de 2 bytes ou 4 bytes. Algumas das mquinas mais novas utilizam inteiros de 8 bytes. Como os resultados da aritmtica de ponteiro dependem do tamanho dos objetos que um ponteiro aponta, a aritmtica de ponteiro dependente da mquina.

Ponteiro Void
Um ponteiro pode ser atribudo a outro se ambos forem do mesmo tipo, exceto quando o ponteiro for um ponteiro para void; Exemplo: no podemos atribuir um endereo de uma varivel int a um ponteiro float; Um ponteiro para void um ponteiro genrico que pode representar qualquer tipo de ponteiro; Todos os tipos de ponteiro podem receber um ponteiro para void, e este pode receber um ponteiro de qualquer tipo; Um ponteiro para void no pode ser desreferenciado; Um ponteiro para int refere-se a 4 bytes de memria em uma mquina com inteiros de 4 bytes;

Ponteiro Void
O compilador ento sabe quanto de espao reservar para um ponteiro do tipo int; Mas o compilador no sabe quanto de espao reservar, na memria, para um tipo void; Um ponteiro para void simplesmente contm um local da memria para um tipo de dado desconhecido; O nmero exato de bytes aos quais o ponteiro se refere no conhecido pelo compilador; Um ponteiro void um ponteiro de propsito geral; Atribuir um ponteiro de um tipo a um ponteiro de outro tipo se nenhum deles for do tipo void * consistem em um erro de sintaxe;

Ponteiro Void
So usados em situaes em que seja necessrio que uma funo receba ou retorne um ponteiro genrico e opere independentemente do tipo de dado apontado; Qualquer endereo pode ser atribudo a um ponteiro void; void *p; O contedo da varivel de um ponteiro void no pode ser acessado por meio desse ponteiro; Para isso necessrio criar outro ponteiro e fazer a converso de tipo na atribuio; Exemplo:

Ponteiro Void
#include <stdio.h> #include <stdlib.h> int main(){ int i=5, *pi; float f=3.2, *pf; void *pv; pv = &i; pi=(int *)pv; //CONVERSO printf("\n *pi = %d \n ", *pi); pv = &f; pf =(float *)pv; //CONVERSO printf("\n *pf = %3.2f \n \n", *pf); system("PAUSE"); return 0; }

Passando argumentos por referncia com ponteiros


Uma funo pode receber diversos argumentos, mas s consegue retornar um nico valor por meio do comando return; Usando ponteiros, possvel que uma funo retorne mais de um valor para a funo chamadora; Duas so as formas de passar argumentos para uma funo: chamada por valor e chamada por referncia; Exemplos:

Passando argumentos por referncia com ponteiros


USANDO CHAMADA POR VALOR #include <stdio.h> #include <stdlib.h> int cubo(int n); int main(){ int numero = 5, resultado; printf("\n Valor da variavel numero: %d ", numero); //passando o nmero por valor funo cubo resultado = cubo(numero); printf("\n Valor da varivel resultado: %d ", resultado); printf("\n \n"); system("PAUSE"); return 0; } //funo para calcular o cubo de um numero inteiro int cubo(int n){ return n*n*n; }

Passando argumentos por referncia com ponteiros


USANDO CHAMADA POR REFERNCIA #include <stdio.h> #include <stdlib.h> void cubo(int *nPtr); int main(){ int numero = 5, resultado; printf("\n Valor da variavel numero: %d ", numero); //passando o nmero por valor funo cubo cubo(&numero); printf("\n Valor da varivel resultado: %d ", numero); printf("\n \n"); system("PAUSE"); *nPtr na verdade a return 0; varivel numero } //funo para calcular o cubo de um numero inteiro void cubo(int *nPtr){ *nPtr = (*nPtr) * (*nPtr) * (*nPtr); }

Passando argumentos por referncia com ponteiros


USANDO CHAMADA POR REFERNCIA #include <stdio.h> #include <stdlib.h> void reajuste(float *, float *); int main(){ float preco, reaj; do { printf("\n Insira o preco atual: "); scanf("%f", &preco); reajuste(&preco, &reaj); printf("\n Novo preco: %3.2f ", preco); printf("\n O aumento foi de %3.2f ", reaj); printf("\n"); } while(preco!=0.0); system("PAUSE"); return 0; } //funo para calcular o cubo de um numero inteiro void reajuste(float *preco, float *reaj){ *reaj = *preco * 0.2; *preco *= 1.2; }