Ponteiros
Ponteiros são as mais poderosas e também as mais controversas ferramentas da linguagem C e C++.
Ponteiros foram abolidos de linguagens novas baseadas em C, como por exemplo Java. Mas, um programa que utiliza ponteiros sabiamente tem um desempenho muito maior, pois ponteiros trabalham diretamente com a memória. Dessa forma, praticamente, podemos manipular toda a quantia de memória do computador, mesmo que seja pouca ou muita.
Ponteiros como o próprio nome diz, é quem aponta. Sua única função, mas de extrema importância, é guardar o endereço de memória de uma variável.
Quando declaramos uma variável e executamos o programa, o sistema operacional se encarrega de alocar (reservar) o espaço necessário para o tipo de dado e “marca” aquele espaço de memória com um nome, que é o nome da variável. O papel do ponteiro é guardar exatamente este endereço.
Como ponteiros guardam endereços de memória, podemos guardar o endereço de qualquer parte da memória, mesmo que este espaço não tenha sido reservado no início da execução do programa.
Podemos declarar ponteiros ou usar referenciamento e dereferenciamento. Ponteiros são declarados como se fossem variáveis, mas contendo um indicador (que é um asterisco).
Por exemplo, se formos criar dois ponteiros, sendo um para um endereço de memória contendo um dado float e outro contendo um int, faríamos:
|
float *ponteiroFloat int *ponteiroInt |
Pronto, agora já temos nossos ponteiros criados. Agora, vamos ver realmente como eles funcionam.
Referência
Referência é quando nos referimos diretamente ao identificador do endereço da memória.
A memória é na verdade uma grande tabela com células sequenciais, cada célula tem seu próprio endereço que segue um padrão contínuo. Ou seja, a primeira célula será 0x00000000, a segunda 0x00000001, a terceira 0x00000002, e assim por diante.
Quando fazemos referência, estamos obtendo exatamente este valor, que é o endereço da célula na memória.
A referência é dada pelo operador &.
Então, vamos imaginar que temos uma variável inteira chamada var1 que vale 100. Iremos criar um ponteiro chamado ptr1 que irá obter o endereço de memória onde está var1.
|
#include <iostream> #include <cstdlib> using namespace std; int main (){ int var1 = 100; int *ptr1; ptr1 = &var1; cout << ptr1 << endl; system ("pause"); } |
Perceba que aqui nós atribuímos a ptr1 o endereço de memória de var1 (&var1) e não o valor contido em var1.
Portanto, o valor de ptr1 não será 100, mas um endereço de memória 0x “algum hexadecimal”. Pois é impossível saber qual será o endereço de uma variável antes da execução do programa.
Dereferência
Dereferência é quando nos referimos ao valor contido no endereço armazenado, ou seja, é o contrário da operação de referência.
A dereferência busca o valor que está no endereço gravado no ponteiro, isso quer dizer que o valor obtido não está no ponteiro, mas no endereço que ele aponta. É importante entender isso porque quando alteramos o valor referenciado pelo ponteiro, na verdade estamos alterando o valor da variável original e não do ponteiro.
A dereferencia é dada pelo operador *.
Ainda usando o exemplo da variável var1.
|
#include <iostream> #include <cstdlib> using namespace std; int main (){ int var1 = 100; int *ptr1; ptr1 = &var1; cout << "O valor contido no endereco de memoria "; cout << ptr1 <<" e "<< *ptr1 << endl; system ("pause"); } |
Portanto, resumidamente, ponteiros se utilizam de referência e dereferência para acessar a memória, sendo a referência (&) o endereço de memória e a dereferência (*) o valor contido no endereço de memória.
Erros Comuns ao Utilizar Ponteiros
Um dos problemas que levaram a extinção do uso de ponteiros em linguagens mais recentes baseadas em C são os erros de lógica cometidos por programadores (inclusive experientes) que muitas vezes levava o programa ao crash ou erro fatal. A seguir, estão alguns problemas comuns que lidamos ao trabalharmos com ponteiros.
Ponteiros devem sempre apontar para algum endereço de memória. Portanto, todo ponteiro deve ser inicializado antes de ser utilizado.
Ex.: int *ptr1; cout << ptr1;
.
Ponteiros não guardam valores, apenas endereços de memória, ou seja, se atribuímos um valor ao ponteiro, esse valor será um novo endereço de memória.
Ex.: ptr1 = &var1; ptr1 = 100;
Nós mudamos o endereço de memória que ptr1 está apontando, agora ele não aponta mais para o endereço devar1, e sim, para o endereço 100. Mas, o que tem no endereço 0x100 ? Esse é um erro muito comum.
Inicializar um ponteiro com o valor de uma dereferência.
Ex.: int *ptr1 = *var1;
.
Esses são alguns dos erros mais comuns, embora praticamente todos os compiladores são capazes de impedir que eles ocorram.
Autor: Denys William Xavier
Este artigo está sob Licença Creative Commons.