C++: Fundamentos de Ponteiros
Última atualização: 2026-08-26
Nas aulas anteriores, variáveis são armazenadas em algum lugar da memória.
Mas onde exatamente fica esse "lugar"? Você pode acessá-lo diretamente?
Ponteiros são variáveis que armazenam endereços — eles permitem manipular a memória diretamente.
1. O que é um Ponteiro?
(1) 1.1 Ponteiros no Dia a Dia
| Analogia da Vida Real | Equivalente em Programa |
|---|---|
| O endereço da sua casa (ex: "Rua Principal, 123...") | Ponteiro (armazena um endereço) |
| Sua casa real (o prédio para o qual o endereço aponta) | Variável (o espaço de memória para o qual o endereço aponta) |
Essência de um ponteiro: Uma variável que armazena um endereço.
(2) 1.2 Por Que Precisamos de Ponteiros?
- Alocação dinâmica de memória (coberto mais tarde com
new/delete) - Funções precisam modificar variáveis externas (passar ponteiros para funções)
- Trabalhar com arrays (nomes de arrays são ponteiros)
- Implementar estruturas de dados complexas (listas encadeadas, árvores, grafos)
2. Declaração e Inicialização de Ponteiros
(1) 2.1 Declarando um Ponteiro
Sintaxe:
▶ Exemplo 2: Exemplo de Código (Dificuldade ⭐)
Type* nomePonteiro;
Saída:
(Saída do programa)
Exemplo:
#include <iostream>
int main() {
int* pInt; // ponteiro para int
double* pDouble; // ponteiro para double
char* pChar; // ponteiro para char
return 0;
}
💡 Ponto-chave: Type* significa "um ponteiro para esse tipo."
(2) 2.2 Operador de Endereço (&)
& é usado para obter o endereço de uma variável.
#include <iostream>
int main() {
int x = 5;
std::cout << "Valor de x: " << x << std::endl;
std::cout << "Endereço de x: " << &x << std::endl; // Saída semelhante a 0x7ffd4a3b
return 0;
}
Saída (exemplo):
Valor de x: 5
Endereço de x: 0x7ffd4a3b
💡 Dica: O formato específico dos endereços depende do sistema e do compilador.
(3) 2.3 Inicializando um Ponteiro
#include <iostream>
int main() {
int x = 5;
int* p = &x; // p aponta para x(p armazena o endereço de x)
std::cout << "Endereço de x: " << &x << std::endl;
std::cout << "Valor de p: " << p << std::endl; // mesmo que &x
return 0;
}
3. Desreferência
(1) 3.1 Operador de Desreferência (*)
* é usado para acessar o valor que um ponteiro aponta.
#include <iostream>
int main() {
int x = 5;
int* p = &x; // p aponta para x
std::cout << "x = " << x << std::endl; // 5
std::cout << "*p = " << *p << std::endl; // 5(Desreferência)
return 0;
}
💡 Ponto-chave: *p é essencialmente x!
(2) 3.2 Modificando uma Variável Através de um Ponteiro
#include <iostream>
int main() {
int x = 5;
int* p = &x;
std::cout << "Antes: x = " << x << std::endl; // 5
*p = 100; // Modifica o valor de x via ponteiro
std::cout << "Depois: x = " << x << std::endl; // 100
return 0;
}
4. Tamanho dos Ponteiros
(1) 4.1 sizeof de um Ponteiro
#include <iostream>
int main() {
int* pInt;
double* pDouble;
char* pChar;
std::cout << "Tamanho de int*: " << sizeof(pInt) << " bytes" << std::endl;
std::cout << "Tamanho de double*: " << sizeof(pDouble) << " bytes" << std::endl;
std::cout << "Tamanho de char*: " << sizeof(pChar) << " bytes" << std::endl;
return 0;
}
Saída (sistema de 64 bits):
Tamanho de int*: 8 bytes
Tamanho de double*: 8 bytes
Tamanho de char*: 8 bytes
💡 Ponto-chave: Todos os ponteiros têm o mesmo tamanho (8 bytes em sistemas de 64 bits, 4 bytes em sistemas de 32 bits) — porque todos armazenam endereços.
5. Ponteiros Nulos (nullptr)
(1) 5.1 O que é um Ponteiro Nulo?
Um ponteiro nulo é um ponteiro que não aponta para nenhum objeto.
#include <iostream>
int main() {
int* p = nullptr; // Ponteiro nulo (recomendado desde C++11)
if (p == nullptr) {
std::cout << "p é um ponteiro nulo" << std::endl;
}
return 0;
}
💡 Dica: Antes do C++11, usava-se NULL (que é essencialmente 0), mas nullptr agora é recomendado.
(2) 5.2 Desreferenciar um Ponteiro Nulo Causa Falha
#include <iostream>
int main() {
int* p = nullptr;
std::cout << *p << std::endl; // ❌ Comportamento indefinido! Pode causar falha
return 0;
}
Resultado da execução:
Segmentation fault (core dumped) // Linux
Ou
Process finished with exit code -1073741819 // Windows
⚠️ Nunca desreferencie um ponteiro nulo!
6. Ponteiros como Parâmetros de Função
(1) 6.1 O Problema: Funções Precisam Modificar Variáveis Externas
#include <iostream>
void modifyValue(int x) {
x = 100; // ❌ modificando uma cópia, não afeta a variável original
}
int main() {
int a = 5;
modifyValue(a);
std::cout << "a = " << a << std::endl; // 5(Inalterado)
return 0;
}
(2) 6.2 Solução: Passar um Ponteiro
#include <iostream>
void modifyValue(int* p) {
*p = 100; // ✅ modifica a variável original via ponteiro
}
int main() {
int a = 5;
modifyValue(&a); // Passa o endereço
std::cout << "a = " << a << std::endl; // 100(Alterado!)
return 0;
}
7. Prática: Trocando Duas Variáveis
▶ Exemplo 1: Implementando swap com Ponteiros (Dificuldade ⭐)
#include <iostream>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 3, y = 5;
std::cout << "Antes da troca: x = " << x << ", y = " << y << std::endl;
swap(&x, &y); // Passa o endereço
std::cout << "Depois da troca: x = " << x << ", y = " << y << std::endl;
return 0;
}
Saída:
Antes da troca: x = 3, y = 5
Depois da troca: x = 5, y = 3
💡 Dica: Depois você aprenderá referências — implementar swap com referências é ainda mais simples.
8. Erros Comuns
(1) 8.1 Desreferenciar um Ponteiro Não Inicializado
#include <iostream>
int main() {
int* p; // ❌ Não inicializado (ponteiro selvagem)
std::cout << *p << std::endl; // ❌ Comportamento indefinido!
return 0;
}
Correção: Inicialize com nullptr, ou aponte para uma variável existente.
(2) 8.2 Incompatibilidade de Tipo de Ponteiro
#include <iostream>
int main() {
int x = 5;
double* p = &x; // ❌ Erro: int* não pode apontar para int
return 0;
}
Mensagem de erro do compilador:
error: cannot convert 'int*' to 'double*' in initialization
▶ Exemplo 3: Ponteiros e Arrays (Dificuldade ⭐)
#include <iostream>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int* p = arr; // nome do array é o endereço do primeiro elemento
for (int i = 0; i < 5; i++) {
std::cout << "arr[" << i << "] = " << *(p + i) << std::endl;
}
return 0;
}
Saída:
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
arr é o endereço do primeiro elemento, equivalente a &arr[0]. Ao percorrer um array com um ponteiro, *(p + i) é equivalente a p[i] ou arr[i].
❓ Perguntas Frequentes
P: Qual a diferença entre ponteiros e referências? R: Será abordado em detalhes mais tarde, mas resumidamente: > - Ponteiros podem apontar para
nullptr; referências devem ser inicializadas > - Ponteiros podem ser reassinalados para apontar para outras variáveis; referências não podem ser religadas uma vez vinculadas > - Ponteiros precisam de*ppara desreferenciar; referências usam o nome da variável diretamenteRecomendação: Prefira referências, a menos que você precise representar "nada" (então use um ponteiro).
P: Por que todos os ponteiros têm o mesmo tamanho? R: Porque ponteiros todos armazenam endereços — o comprimento de um endereço depende do sistema (4 bytes em 32 bits, 8 bytes em 64 bits). P: Qual a diferença entre um ponteiro nulo e um ponteiro selvagem? R:> - Ponteiro nulo: aponta explicitamente para
nullptr(seguro) > - Ponteiro selvagem: aponta para um endereço aleatório, ou para memória liberada (perigoso!)CPPint* p1 = nullptr; // Ponteiro nulo (seguro) int* p2; // ❌ Ponteiro selvagem (não inicializado)
P: O que é mais importante sobre fundamentos de ponteiros? R: Entenda os conceitos centrais primeiro, depois reforce-os através de exemplos práticos.
📖 Resumo
- Ponteiros são variáveis que armazenam endereços
- Declaração:
Type* nomePonteiro; - Obter endereço:
&nomeVariavel - Desreferência:
*nomePonteiro - Ponteiro nulo:
nullptr - Nunca desreferencie um ponteiro nulo ou um ponteiro selvagem
📝 Exercícios
-
Básico (Dificuldade ⭐): Declare uma variável
intx = 10, depois declare um ponteiroint*papontando parax. Exiba o valor dexe*p. -
Intermediário (Dificuldade ⭐⭐): Escreva uma função
void addTen(int* p)que adiciona 10 à variável apontada pelo ponteiro. Teste-a emmain. -
Desafio (Dificuldade ⭐⭐⭐): Escreva um programa que declare três variáveis
inta, b, c, e três ponteiros apontando para cada uma delas. Use os ponteiros para alterar todas as três variáveis para 100, depois exiba-as.
- Ponteiros são variáveis que armazenam endereços de memória
- & obtém o endereço, * desreferencia para acessar o valor apontado
- Declaração: Type* nomePonteiro (ex: int* p;)
- Ponteiro nulo nullptr (C++11) substitui NULL
- Ponteiros apontando para a mesma memória — alterar um afeta o outro
9. 🚀 Próximo Passo
Agora que você aprendeu fundamentos de ponteiros, vamos avançar para Ponteiros e Arrays (Aula 23) — entendendo que nomes de arrays são ponteiros, e aritmética de ponteiros.