Você está na página 1de 12

Ponteiro (programao)

Ponteiro (programao)
Em programao, um ponteiro ou apontador um tipo de dado de uma linguagem de programao cujo valor se refere diretamente a um outro valor alocado em outra rea da memria, atravs de seu endereo. Um ponteiro uma simples implementao do tipo referncia da cincia da computao.

Arquitetura
Ponteiros so uma abstrao da capacidade de endereamento fornecidas pelas arquiteturas modernas. Em termos simples, um endereo de memria, ou ndice numrico, definido para cada unidade de memria no sistema, no qual a unidade tipicamente um byte ou uma word, o que em termos prticos transforma toda a memria em um grande vetor.[1] Logo, a partir de um endereo, possvel obter do sistema o valor armazenado na unidade de memria de tal endereo. O ponteiro um tipo de dado que armazena um endereo. Na maioria das arquiteturas, um ponteiro grande o suficiente para indexar todas as unidades de memria presentes no sistema. Isso torna possvel a um programa tentar acessar um endereo que corresponde a uma rea invlida ou desautorizada da memria, o que chamado de falha de segmentao. Por outro lado, alguns sistemas possuem mais unidades de memria que endereos. Nesse caso, utilizado um esquema mais complexo para acessar diferentes regies da memria, como o de segmentao ou paginao. Para fornecer uma interface consistente, algumas arquiteturas fornecem E/S mapeada em memria, o que permite que enquanto alguns endereos so referenciados como reas de memria, outros so referenciados como registradores de dispositivos do computador, como equipamentos perifricos.

Usos de Ponteiros
Ponteiros so diretamente suportados sem restries em C, C++, D e Pascal, entre outras linguagens. So utilizados para construir referncias, elemento fundamental da maioria das estruturas de dados, especialmente aquelas no alocadas em um bloco contnuo de memria, como listas encadeadas, rvores ou grafos. Ao lidar com arranjos, uma operao crtica o clculo do endereo para o elemento desejado no arranjo, o que feito atravs da manipulao de ponteiros. De fato, em algumas linguagens (como C), os conceitos de "arranjo" e "ponteiro" so intercambiveis. Em outras estruturas de dados, como listas encadeadas, ponteiros so usados como referncias para intercalar cada elemento da estrutura com seus vizinhos (seja anterior ou prximo). Ponteiros tambm so utilizados para simular a passagem de parmetros por referncia em linguagens que no oferecem essa construo (como o C). Isso til se desejamos que uma modificao em um valor feito pela funo chamada seja visvel pela funo que a chamou, ou tambm para que uma funo possa retornar mltiplos valores. Linguagens como C, C++ e D permitem que ponteiros possam ser utilizados para apontar para funes, de forma que possam ser invocados como uma funo qualquer. Essa abordagem essencial para a implementao de modelos de re-chamada (callback), muito utilizados atualmente em bibliotecas de rotinas para manipulao de interfaces grficas. Tais ponteiros devem ser tipados de acordo com o tipo de retorno da funo o qual apontam. Ponteiros para funo se assemelham a functores, ainda que o conceito funo objeto seja mais abrangente.

Ponteiro (programao)

Exemplos
Abaixo mostrado o exemplo da declarao de uma lista encadeada em C, o que no seria possvel sem o uso de ponteiros: #define LISTA_VAZIA NULL /* a lista encadeada vazia representada por NULL */ struct link { void *info; /* contedo do n da lista */ struct link *prox; /* endereo do prximo n da lista; LISTA_VAZIA se este o ltimo n */ }; Note que essa definio recursiva de ponteiros a mesma que a definida em Haskell: data Link a = Nil {- lista vazia -} | Cons a (Link a) {- a cons n de um valor de tipo a e outro n -} A definio com referncias, por outro lado, possui checagem de tipo, sem confuso de smbolos. Por essa razo, estruturas de dados em C geralmente so utilizadas com o auxlio de funes de encapsulamento, que so cuidadosamente verificadas contra erros. A mesma definio de lista encadeada pode ser codificada em Fortran utilizando ponteiros, como segue: type real_list_t real :: sample_data(100) type (real_list_t), pointer :: next => null () end type type (real_list_t), target :: my_real_list type (real_list_t), pointer :: real_list_temp real_list_temp => my_real_list do read (1,iostat=ioerr) real_list_temp%sample_data if (ioerr /= 0) exit allocate (real_list_temp%next) real_list_temp => real_list_temp%next end do Vetores em C so somente ponteiros para reas consecutivas da memria. Logo: #include <stdio.h> int main() { int arranjo[5] = { 2, 4, 3, 1, 5 }; printf("%p\n", arranjo); printf("%d\n", arranjo[0]); arranjo, 2 /* imprime o endereo do arranjo */ /* imprime o primeiro elemento do */

Ponteiro (programao) printf("%d\n", *arranjo); /* imprime o primeiro inteiro do endereo apontado pelo arranjo, que o primeiro elemento, 2 */ printf("%d\n", arranjo[3]); /* imprime o quarto elemento do arranjo, 1 */ printf("%p\n", arranjo+3); /* imprime o terceiro endereo aps o incio do arranjo */ printf("%d\n", *(arranjo+3)); /* imprime o valor no tercero endereo aps o incio do arranjo, 1 */

return 0; } Tal operao chamada aritmtica de ponteiros, e usada em ndices de ponteiros. O uso dessa tcnica em C e C++ discutido posteriormente neste mesmo artigo. Ponteiros podem ser usados para passar variveis por referncia, permitindo que seus valores modificados tenham efeito no escopo anterior do programa, como exemplificado no cdigo C abaixo: #include <stdio.h> void alter(int *n) { *n = 120; } int main() { int x = 24; int *endereco= &x; /* o operador '&' (leia-se "refernca") retorna o endereo de uma varivel */ printf("%d\n", x); /* mostra x */ printf("%p\n", endereco); /* mostra o endereo de x */ alter(&x); /* passa o endereo de x como referncia, para alterao */ printf("%d\n", x); /* mostra o novo valor de x */ printf("%p %p\n", endereco, &x); /* note que o endereo de x no foi alterado */ return 0; } Ponteiros podem ser usados para apontar para funes, permitindo, por exemplo, a passagem de funes como parmetro de outras funes. O cdigo em C abaixo demonstra tal funcionalidade: #include <stdio.h> int soma = 0; int produto = 1; void fsoma(int valor) /* armazena a soma */ /* armazena o produto */

Ponteiro (programao) { soma += valor; } void fproduto(int valor) { produto *= valor; } void mapeamento_funcao_lista(lista *L, void (*funcaoptr)(int)) { lista_no *no; no = L->inicio; while (no != NULL) { funcaoptr(no->valor); /* invoca o ponteiro de funo */ no = no->proximo; } } int main() { lista *L; /* ... preenche a lista com valores ... */ mapeamento_funcao_lista(L, fsoma); /* calcula o somatrio dos elementos da lista */ mapeamento_funcao_lista(L, fproduto); /* calcula o produtrio dos elementos da lista */ printf("Somatorio: %d\nProdutorio %d\n", soma, produto); /* imprime na tela os resultados */ return 0; /* retorno bem sucedido */ } Note que, no exemplo acima, a rotina para a execuo de cdigo para cada elemento da lista (tcnica conhecida como mapeamento) implementada somente uma vez. O mapeamento novamente exemplificado abaixo em uma rotina para determinar se elementos em uma lista so pares ou mpares, codificado em ML: fun map(F, nil) = nil | map(F, x::xs) = F(x)::map(F, xs); map(fn x => x mod 2, [1,2,3,4,5,6,7,8,9]); A funo map() recebe como entrada um valor e uma lista. Neste caso, o valor passado uma funo (x mod 2, uma implementao utilizando clculo lambda para retornar se dado valor par). Tal funo mapeada recursivamente, sendo executada em cada elemento da lista.

Ponteiro (programao)

Situaes de uso
Os ponteiros so necessrios para a alocao dinmica de memria, para seqncias de dados alocados e para a passagem ou o retorno atravs referncia. Neste ltimo importante citar a relevncia no desempenho, pois muito mais rpido alocar um ponteiro para um objeto de memria j existente do que alocar o objeto inteiro novamente. Alm do mais, alocando o objeto novamente no podemos alterar o original.

Ponteiros tipados e converso


Em vrias linguagens, ponteiros possuem a restrio adicional de apontar para objetos de um tipo especfico de dado. Por exemplo, um ponteiro pode ser declarado para apontar para um inteiro. A linguagem tentar prevenir o programador de apontar para objetos que no so inteiros, ou derivados de ponteiros, como nmeros de ponto flutuante, eliminando alguns tipos bsicos de erro cometidos por programadores. Apesar disso, poucas linguagens definem tipagem restrita de ponteiros, pois programadores freqentemente se encontram em situaes nas quais desejam tratar um objeto de um tipo como se tivesse outro. Nesses casos, possvel converter o tipo de um ponteiro. Algumas converses so sempre seguras, enquanto outras so perigosas, possivelmente resultando em comportamento incorreto do sistema. Apesar de geralmente ser impossvel determinar em tempo de compilao se tais converses so seguras, algumas linguagens armazenam informaes sobre tipagem em tempo de execuo (como o processo RTTI do C++), que podem ser usadas para confirmar se tais converses perigosas so vlidas, em tempo de execuo. Outras linguagens simplesmente aceitam uma aproximao conservadora de converses seguras, ou apenas no aceitam converses.

Perigos na utilizao de ponteiros


Como ponteiros permitem ao programa acessar objetos que no so explicitamente declarados previamente, permitem uma variedade de erros de programao. Apesar disso, o poder fornecido por eles to grande que existem tarefas computacionais que so difceis de ser implementadas sem sua utilizao. Para ajudar nesse aspecto, vrias linguagens criaram objetos que possuem algumas das funcionalidades teis de ponteiros, ainda que evitando alguns tipos de erro. Um grande problema com ponteiros que enquanto so manipulados como nmeros, podem apontar para endereos no utilizados, ou para dados que esto sendo usados para outros propsitos. Vrias linguagens, incluindo a maioria das linguagens funcionais e linguagens recentes, como C++ e Java, trocaram ponteiros por um tipo mais ameno de referncia. Tipicamente chamada de "referncia", pode ser usada somente para referenciar objetos sem ser manipulada como nmero, prevenindo os tipos de erros citados anteriormente. ndices de vetores so lidados como um caso especial. As primeiras verses de Fortran e Basic omitiam completamente o conceito de ponteiros.

Ponteiro selvagem
Um ponteiro selvagem (tambm chamado de apontador pendente) no possui endereo associado. Qualquer tentativa em us-lo causa comportamento indefinido, ou porque seu valor no um endereo vlido ou porque sua utilizao pode danificar partes diferentes do sistema. Em sistemas com alocao explcita de memria, possvel tornar um ponteiro invlido ao desalocar a regio de memria apontada por ele. Esse tipo de ponteiro perigoso e sutil, pois um regio desalocada de memria pode conter a mesma informao que possua antes de ser desalocada, mas tambm pode ser realocada e sobreescrita com informao fora do escopo antigo. Linguagens com gerenciamento automtico de memria previnem esse tipo de erro, eliminando a possibilidade de ponteiros invlidos e de vazamentos de memria. Algumas linguagens, como C++, suportam ponteiros inteligentes (smart pointers), que utilizam uma forma simples de contagem de referncias para ajudar no rastreamento de alocao de memria dinmica, alm de atuar como referncia.

Ponteiro (programao)

Ponteiro nulo
Um ponteiro nulo possui um valor reservado, geralmente zero, indicando que ele no se refere a um objeto. So usados freqentemente, particularmente em C e C++, para representar condies especiais como a falta de um sucessor no ltimo elemento de uma lista ligada, mantendo uma estrutura consistente para os ns da lista. Esse uso de ponteiros nulos pode ser comparado ao uso de valores nulos em bancos de dados relacionais e aos valors Nothing e Maybe em mnadas da programao funcional. Em C, ponteiros de tipos diferentes possuem seus prprios valores nulos, isto , um ponteiro nulo do tipo char e diferente de um ponteiro nulo do tipo int. Como se referem ao nada, uma tentativa de utilizao causa um erro em tempo de execuo que geralmente aborta o programa imediatamente (no caso do C com uma falha de segmentao, j que o endereo literalmente aponta para uma regio fora da rea de alocao do programa). Em Java, o acesso a uma referncia nula lana a exceo Java.lang.NullPointerException. Ela pode ser verificada, ainda que a prtica comum tentar se assegurar que tais excees nunca ocorram. Um ponteiro nulo no pode ser confundido com um ponteiro no inicializado: ele possui um valor fixo, enquanto um ponteiro no inicializado pode possuir qualquer valor. Uma comparao entre dois ponteiros nulos distintos sempre retorna verdadeiro.

Exemplos
O seguinte exemplo demonstra um ponteiro selvagem: int main(void) { char *p1 = (char *) malloc(sizeof(char)); // aloca memria e inicializa o ponteiro printf("p1 aponta para: %p\n", p1); // aponta para algum lugar da memria heap printf("Valor de *p1: %c\n", *p1); // valor (indefinido) de algum lugar na memria heap char *p2; printf("Endereco de p2: %p\n", no ser um endereo vlido // ponteiro selvagem // valor indefinido, pode

p2);

// se voc for sortudo, isso ir causar uma exceo de endereamento printf("Valor de *p2: %c\n", *p2); // valor aleatrio em endereo aleatrio return 0; } O seguinte exemplo demonstra um ponteiro invlido por mudana de escopo: #include <stdio.h> #include <stdlib.h> int maIdeia(int **p) { int x = 1; // p um ponteiro para um ponteiro de inteiro // aloca um inteiro na pilha

Ponteiro (programao) **p = x; aponta *p = &x; return x; indefinido } // define o valor de x para o inteiro que p // faz o ponteiro que p aponta apontar para x // aps retornar x estar fora de escopo e

int main(void) { int y = 0; int *p1 = &y; para y int *p2 = NULL; utilizado printf("Endereco dep1: %p\n", p1); y printf("Valor de *p1: %d\n", *p1); y = maIdeia(&p1); // // // //

// ponteiro inicializado // um bom hbito a ser // imprime o endereo de // imprime o valor de y // muda y e muda p1

p1 agora aponta para onde x estava O lugar onde x estada ser sobreescrito, por exemplo, na prxima interupo, ou na prxima sub-rotima, como abaixo...

// algum outro cdigo que utiliza a pilha p2 = (int *)malloc(5*sizeof(int)); // isso no ir abortar, mas o valor impresso imprevisvel printf("Valor de *p1: %p\n", *p1); // imprime o valor onde x estava return 0; } Um problema muito comum usar um ponteiro para a memria heap depois que a memria foi desalocada, como no prximo exemplo: #include <stdio.h> #include <stdlib.h> int main(void) { int *p1 = (int *)malloc(sizeof(int)); para a memria heap int *p2 = p1; *p1 = 0; printf("Endereco de p2: %p\n", p2); printf("Valor de *p2: %d\n", *p2);

// inicializa o ponteiro // // // // faz uma cpia inicializa o valor aponta para a heap deve imprimir 0

Ponteiro (programao) free(p1); // desaloca a memria .... // algum outro cdigo, possivelmente utilizando a heap // p2 ainda aponta para o local original da alocao, mas impossvel saber o que est l printf("Valor de *p2: %d\n", *p2); // uso invlido de p2 return 0; } Outra maneira de utilizar incorretamente ponteiros acessar fora da estrutura de dados a qual eles apontam, como no exemplo a seguir: #include <stdio.h> #include <stdlib.h> int main(void) { int y = 5; int *p1 = &y; para y printf("Endereco de p1: %p\n", p1); printf("Valor de *p1: %d\n", *p1); p1 = p1 + y; ponteiros printf("Valor de *p1: %p\n", *p1); y return 0; }

// cria a varivel // inicializa o ponteiro // endereo de y // valor de y // aritmtica vlida de // p1 no aponta mais para

Se um ponteiro usado para escrever alm do final de uma regio local, a pilha de execuo pode ser destruda. No caso abaixo, o problema provavelmente se manifestar quando o programa principal retornar: #include <stdio.h> #include <stdlib.h> // copia a origem para o destino, sem checagem de tamanho void strcopy(char *d, char *s) { while (*d++ = *s++) // copia at que '\0' encontrado ; } int main(void) { char y[3]; // cria uma regio local char *p1 = (char *)malloc(10*sizeof(char)); // outra regio local na memria heap

Ponteiro (programao) p1[9] = '\0'; na maior regio strcopy(y, p1); regio local free(p1); return 0; acontecem } // insere o terminador // sobreescreve a

// agora coisas ruins

Suporte em linguagens de programao


Vrias linguagens de programao suportam algum tipo de ponteiro, ainda que algumas restringem sua ao mais que outras. Se um ponteiro significativamente abstrato de forma a no poder ser manipulado como endereo, a estrutura de dados resultante no mais considerada um ponteiro, e sim uma referncia.

Ada
Ada uma linguagem fortemente tipada no qual todos os ponteiros so tipados e somente converses seguras de tipo so permitidas. Todos os ponteiros so por padro inicializados com null, e qualquer tentativa em acessar informao atravs de um ponteiro para null causa uma exceo. Ponteiros em Ada so chamados "tipos de acesso". Ada-83 no permitia aritmtica em tipos de acesso (ainda que vrios compiladores a forneciam como uma funcionalidade fora do padro), mas Ada-95 suporta aritmtica segura em tipos de acesso pelo pacote System.Storage_Elements.

C e C++
Em C e C++, ponteiros so variveis que armazenam endereos e podem ser nulas. Cada ponteiro possui um tipo para o qual aponta, mas converses de tipo podem ser feitas. Um ponteiro especial, chamado ponteiro void, aponta para um objeto de tipo desconhecido e no pode ser utilizado isoladamente sem a converso para outro tipo de dado. O endereo do ponteiro pode ser diretamente manipulado ao realizar uma converso para o tipo inteiro. C++ suporta completamente os ponteiros e as converses de tipo do C. Tambm suporta um novo grupo de operadores para converso de tipos que ajudam a encontrar algumas das mais perigosas converses em tempo de compilao e execuo. A biblioteca padro do C++ ainda fornece auto ptr, uma espcie de ponteiro inteligente que pode ser utilizado em algumas situaes como uma alternativa segura aos ponteiros primitivos do C. A linguagem tambm suporta referncias, uma verso mais abstrata de ponteiros. Aritmtica de ponteiros em C e C++ Em ambas as linguagens a aritmtica de ponteiros quase irrestrita: adicionar ou subtrair de um ponteiro o movimenta tendo como unidade o tamanho do tipo de dados para o qual ele aponta. Por exemplo, somar 2 a um ponteiro de inteiros de 4 bytes ir increment-lo em 8. Isso faz com que o incremento de um ponteiro o posicione para o prximo elemento em um arranjo, o que geralmente o resultado intencionado. Aritmtica entre ponteiros no pode ser feita em ponteiros para void. possvel tambm fazer a subtrao entre dois ponteiros (o resultado ser a distncia entre ambos). No entanto, no possvel fazer a adio de dois ponteiros. Aritmtica de ponteiros fornece ao programador uma maneira nica em lidar com diferentes tipos: adicionar ou subtrair o nmero de elementos ao invs de lidar com bytes. Em particular, o C define explicitamente que a sintaxe a[n], que representa o n-simo elemento de um vetor apontado por a, equivalente a *(a+n), que o contedo do elemento apontado por a+n.

Ponteiro (programao) Ainda que poderosa, a aritmtica de ponteiros pode ser fonte de erros. Ela tende a confundir programadores iniciantes, forando-os em diferentes contextos: um expresso pode ser de aritmtica comum ou de ponteiros, e as vezes fcil confundir uma da outra. Contra esse tipo de situao, vrias linguagens de alto nvel modernas (como o Java), no permitem acesso direto memria usando endereos.

10

C#
Em C#, ponteiros so suportados somente com algumas condies: qualquer bloco de cdigo que inclua ponteiros deve ser marcado com a palavra-chave unsafe. Tais blocos geralmente requisitam permisses mais altas de segurana para poderem ser executados. A sintaxe a mesma do C++, e o endereo apontado pode ser tanto memria gerenciada quanto no gerenciada. Apesar disso, ponteiros para memria gerenciada devem ser declarados usando a palavra-chave fixed, o que previne que o coletor de lixo mova o objeto apontado enquanto o ponteiro est no escopo, mantendo o endereo do ponteiro vlido por toda a sua existncia. A plataforma .NET inclui vrias classes e mtodos nos espaos de nome System e System.Runtime.InteropServices (como a classe Marshal) que convertem tipos .NET (como por exemplo System.String) para vrios tipos no gerenciados de ponteiro (como por exemplo LPWSTR ou ponteiro void), e vice-versa, permitindo comunicao com cdigo no gerenciado.

D
A linguagem D derivada do C e C++, e suporta completamente os ponteiros e as converses de tipo de C. Apesar disso, D tambm oferece vrias estruturas como enlace foreach, parmetros fora da funo, tipos de referncia e manipulao avanada de arranjos, o que evita utilizar ponteiros para a maioria das rotinas.

Fortran
A linguagem Fortran-90 introduziu o conceito de ponteiro fortemente tipado, que armazenam mais que somente um endereo de memria. Eles tambm encapsulam limites inferiores e superiores das dimenso de arranjos, alm de outros meta-dados. Um operador de associao (=>) usado para associar um ponteiro (POINTER) a uma varivel que possuiu um atributo TARGET. A instruo de alocao (ALLOCATE) tambm pode ser usada para associar um ponteiro a um bloco de memria. Fortran-2003 tambm suporte ponteiros para procedimentos. Da mesma maneira, como parte da caracterstica de interoperabilidade com o C, suporta converso de ponteiros do C para ponteiros Fortran, e vice-versa.

Pascal
Pascal implementa ponteiros para serem teis, limitados e relativamente seguros. Isso ajuda a encontrar erros feitos por pessoas novas em programao, como obter o valor de um ponteiro utilizando o tipo de dado errado. Entretanto, um ponteiro pode ser convertido de um tipo para outro. Aritmtica de ponteiros irrestrita: adicionar ou subtrair um ponteiro o move pela razo do nmero de bytes, mas usar os procedimentos padro Inc e Dec o move pela razo do tamanho do tipo de dado ao qual o est declarado. Tentar obter o valor de um ponteiro nulo (nil) ou no inicializado lana uma exceo em modo protegido. Parmetros de funes podem ser passados utilizando ponteiros (como parmetros VAR).
[1] Luiz Lima Jr. (2007). Ponteiros (http:/ / www. ppgia. pucpr. br/ ~laplima/ aulas/ tp/ 12_ponteiros. html). PPGIA, PUCPR. Pgina visitada em 14 de outubro de 2007. "A memria do computador pode ser considerada uma seqncia de clulas de memria, cada uma de um tamanho mnimo que o computador capaz de gerenciar (geralmente um byte). Estas clulas de memria de 1 byte so numeradas de forma consecutiva. Assim, cada clula pode ser facilmente localizada na memria porque tem um endereo nico."

Ponteiro (programao)

11

Ver tambm
Linguagem de programao Estrutura de dados Gerenciamento automtico de memria Falha de segmentao Null (programao) Ponteiro inteligente

Fontes e Editores da Pgina

12

Fontes e Editores da Pgina


Ponteiro (programao) Fonte: http://pt.wikipedia.org/w/index.php?oldid=21851707 Contribuidores: Cesperanca, Daemorris, Faustino.F, Flivon, Leonardo.stabile, Luckas Blade, Luiz Jr, Lus Felipe Braga, Nuno Tavares, Petryx, Rafael.afonso, SaintCahier, ThiagoRuiz, 30 edies annimas

Licena
Creative Commons Attribution-Share Alike 3.0 Unported http:/ / creativecommons. org/ licenses/ by-sa/ 3. 0/

Você também pode gostar