Atualizado pela última vez em junho de 2026.
Ponteiros são números naturais. Eles são usados para indicar um endereço na memória, da mesma forma que um índice é usado para indicar uma posição de um vetor. A diferença principal é que usando ponteiros, não existe uma nome de vetor que indica o contexto do índice, o contexto é sempre a memória toda. Portanto, podemos também dizer que ponteiros são endereços.
Usando vetores, os vários itens não tinham nomes individuais, então era preciso um índice para trabalhar com um item do vetor usando o operador []. O operador [] (colchetes, quando numa expressão) é uma função que recebe um vetor e uma posição, para retornar o item do vetor naquela posição. Com ponteiros, é a mesma coisa, vamos precisar deles principalmente para trabalhar com variáveis que não têm nome.
Na função main abaixo, temos duas variáveis a e b, que são variáveis dinâmicas na pilha. Quando a execução do programa chegar na linha da declaração da variável, um espaço de memória vai ser alocado para armazenar o valor da variável. Quando a execução do programa deixar o trecho em que a variável foi declarada, o espaço de memória dela vai ser desalocado automaticamente.
int main() {
int a;
int b;
cout << a * b << endl;
}
Agora vamos usar variáveis dinâmicas no monte. As variáveis que usam essa estratégia de alocação de memória são alocadas quando o comando new for executado e são desalocadas quando o comando delete for executado. Isso permite que o espaço de armazenamento persista através da execução de trechos diferentes de código.
int main() {
int* ptA = new int;
int* ptB = new int;
cout << (*ptA) * (*ptB) << endl;
delete ptA;
delete ptB;
}
Esse código agora tem 4 variáveis:
Agora, as variáveis que são os fatores da multiplicação não têm nome. Para usá-las na multiplicação, vamos precisar das variáveis ptA e ptB. Usando o valor de ptA, podemos saber o valor do primeiro fator da multiplicação. Usando o valor de ptB, podemos saber o valor do segundo fator multiplicação. O operador de derreferencia (*) serve para isso; ele recebe um ponteiro para uma variável (do seu lado direito) e retorna a variável apontada pelo ponteiro, ou seja, *ptA é o valor do primeiro fator da multiplicação, que não tem nome, mas pode usado porque sabemos que está no endereço ptA.
As variáveis sem nome são desalocadas pelo comando delete. O comando delete ptA, não desaloca ptA, ele desaloca a variável apontada por ptA.
Infelizmente, na linguagem C++, o * é usado para várias coisas diferentes. No código acima, vimos ele usado como operador de multiplicação (que recebe dois fatores e retorna o produto) e como operador de derreferência. Queremos que as duas derreferências sejam feitas antes da multiplicação, por isso eu coloquei as duas derreferências entre parênteses. Também vimos o * aparecendo nas declarações; lá ele é o nome do tipo ponteiro (int* é o nome do tipo ponteiro para int).
Para ajudar na organização, algumas convensões de estilo foram usadas:
Assim, é importante lembrar que quando o asterisco aparece numa declaração ele é só um nome de tipo. Quando ele aparece numa expressão (de ponteiros), ele é uma função que recebe um ponteiro e retorna a variável apontada pelo ponteiro.
Além do operador *, o operador & também é usado em código relacionado com ponteiros e alocação dinâmica, e em C++ o & também tem vários significados. Quando o & aparece numa declaração, ele indica ao compilador que aquela variável não vai ter um espaço próprio de memória, em vez disso, ela vai usar o espaço de armazenamento de outra variável que já existia.
int funcao(int& param) {
// Nesta função, param (parâmetro formal) não tem um espaço próprio de memória, ela
// usa o mesmo espaço de memória da variável usada na ativação (parâmetro real).
// Chamado de passagem de parâmetro por referência.
param = 7; // usando param normalmente
return x;
}
O valor que uma função retorna é também um parâmetro, porém sem nome. Esse parâmetro também pode usar o armazenamento de outra coisa:
int& funcao() {
// O valor que a função retorna não tem um espaço próprio de memória, vai ser usado
// o espaço de memória da coisa que aparecer no comando return.
// Normalmente colocamos variáveis temporárias no return, e isso é um problema porque não se pode
// compartilhar o espaço com uma coisa que vai ser desalocada.
return algumaCoisa; // nada incomum na expressão do return
}
int& funcao(int& param) {
// Este exemplo está mais realista porque param (parâmetro formal) e o parâmetro de retorno compartilham
// o espaço de memória com o parâmetro passado (parâmetro real) e esse espaço não será desalocado
// quando a função terminar de executar. A função pode modificar o valor guardado em param. Quem
// chamou a função pode acessar o novo valor tanto pelo parâmetro real quanto pelo parâmetro de
// retorno (se quiser fazer uma cópia dele).
return param;
}
int& x = y; // As variáveis x e y são do tipo int e usam o mesmo espaço na memória
Quando o & aparece numa expressão, ele é o operador de referência (uma função que recebe uma variável e retorna o endereço daquela variável, ou seja, retorna um ponteiro para aquela variável). A operação de derreferência é o inverso da operação de referência.
int a;
int* ptA = &a; // ptA aponta para a
Agora note no código abaixo que Processar não recebe a variável a. Ela recebe o retorno do &. O & retorna o endereço de a, numa variável do tipo int* que não tem nome.
int a = 3;
int b = Processar(&a);
Isso não é passagem por referência, mas permite que a função Processar modifique o valor de a. Isso pode ser considerado mais legível que a passagem por referência, porque o & no parâmetro real já chama a atenção, indicando que o se espera mudança no valor de a. É importante atentar para essa possiblidade de mudança sem que seja necessário conferir a implementação de Processar.
int Processar(int* param) {
return ...;
}
Na declaração de Processar acima, vemos que o parâmetro formal é do tipo int* e esse parâmetro tem seu próprio espaço de memória (passagem por cópia).
Esta página é mantida por Bruno Schneider para a disciplina de IAlg