Ponteiros em C++
Para Estudantes de Engenharia
Tópicos
- Sistema Hexadecimal
- Operadores * e &
- Declaração e uso de ponteiros
- Ilustração da memória do computador
- Aritmética de ponteiros
- Passagem de parâmetros por referência
- Ponteiros para ponteiros
O que é Hexadecimal?
- Sistema de numeração de base 16
- Dígitos: 0-9 e A-F (A=10, B=11, ..., F=15)
- Exemplo: 0x1A3 = 1*16² + 10*16¹ + 3*16⁰ = 256 + 160 + 3 = 419 (decimal)
- Útil para representar grandes números de forma compacta
Endereços de Memória e Hexadecimais
- Endereços de memória são geralmente representados em hexadecimal
- Sistema hexadecimal: base 16 (0-9 e A-F)
- Exemplo: 0x7ffd5ca30a5c
Operador *
- O operador * tem dois usos principais com ponteiros:
- 1. Na declaração: indica que a variável é um ponteiro
- 2. Na desreferenciação: acessa o valor apontado pelo ponteiro
int* ptr; // Declaração: ptr é um ponteiro para int
*ptr = 10; // Desreferenciação: atribui 10 ao valor apontado por ptr
Operador &
- O operador & é usado para obter o endereço de uma variável
- Retorna o endereço de memória onde a variável está armazenada
int num = 5;
int* ptr = # // ptr recebe o endereço de num
Declaração e Uso de Ponteiros
int num = 10;
int* ptr = # // Declaração e inicialização correta
cout << "Valor de num: " << num << endl;
cout << "Endereço de num: " << ptr << endl;
cout << "Valor apontado por ptr: " << *ptr << endl;
Ilustração da Memória do Computador
| Endereço |
Valor |
Variável |
| 0x1000 |
10 |
int a |
| 0x1004 |
20 |
int b |
| 0x1008 |
0x1004 |
int* ptr |
| 0x100C |
30 |
int c |
O ponteiro 'ptr' (0x1008) armazena o endereço de 'b' (0x1004)
Animação de Ponteiros em C++
Representação da Memória
Aritmética de Ponteiros
- O compilador aloca elementos de arrays de maneira sequencial na memória
- Ao incrementar um ponteiro, o compilador entende que queremos apontar para o próximo espaço de memória do tipo do ponteiro
int arr[] = {10, 20, 30, 40, 50};
int* p = arr;
cout << "*p: " << *p << endl; // Imprime 10
cout << "*(p+1): " << *(p+1) << endl; // Imprime 20
cout << "*(p+2): " << *(p+2) << endl; // Imprime 30
Ilustração de Array na Memória
| Endereço |
Valor |
Elemento |
| 0x1000 |
10 |
arr[0] |
| 0x1004 |
20 |
arr[1] |
| 0x1008 |
30 |
arr[2] |
| 0x100C |
40 |
arr[3] |
| 0x1010 |
50 |
arr[4] |
p+1 aponta para 0x1004, p+2 para 0x1008, etc.
Passagem de Parâmetros por Referência
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int x = 5, y = 10;
swap(&x, &y);
cout << "x: " << x << ", y: " << y << endl; // x: 10, y: 5
Ponteiros para Ponteiros
- Um ponteiro para ponteiro é uma variável que armazena o endereço de outro ponteiro
- Declaração: use dois asteriscos, por exemplo: int**
- Útil para arrays multidimensionais e estruturas de dados complexas
Ponteiros para Ponteiros - Exemplo
int num = 42;
int* ptr = # // Ponteiro para int
int** ptr_to_ptr = &ptr; // Ponteiro para ponteiro para int
cout << "Valor de num: " << num << endl;
cout << "Endereço de num: " << ptr << endl;
cout << "Valor apontado por ptr: " << *ptr << endl;
cout << "Endereço de ptr: " << ptr_to_ptr << endl;
cout << "Valor apontado por ptr_to_ptr: " << *ptr_to_ptr << endl;
cout << "Valor de num através de ptr_to_ptr: " << **ptr_to_ptr << endl;
Ilustração: Ponteiros para Ponteiros na Memória
| Endereço |
Valor |
Variável |
| 0x1000 |
42 |
int num |
| 0x1004 |
0x1000 |
int* ptr |
| 0x1008 |
0x1004 |
int** ptr_to_ptr |
ptr_to_ptr (0x1008) → ptr (0x1004) → num (0x1000) = 42
Arrays 2D vs int** em C++
- Erro comum: tentar usar
int** para apontar para int matriz[3][3]
- São tipos fundamentalmente diferentes
- Possuem layouts de memória distintos
- Não podem ser usados de forma intercambiável com segurança
Layout de Memória: Array 2D
int matriz[3][3]; // Bloco contíguo de memória
- Armazenado como um bloco contínuo
- Tamanho conhecido em tempo de compilação
- Dimensões fixas
Layout de Memória: int**
int** ptr; // Ponteiro para ponteiro
- Memória não contígua
- Requer alocação dinâmica
- Dimensões flexíveis
Decaimento de Tipo em Arrays
int matriz[3][3];
Decai para:
int (*)[3] // Ponteiro para array de 3 inteiros
E não para:
int** // Isso está incorreto!
Erros Comuns a Evitar
int matriz[3][3];
int** p = (int**)matriz; // ERRADO!
Problemas:
- Comportamento indefinido
- Possíveis crashes
- Corrupção de memória
- Código não portável
Quando Usar Cada Tipo
Array 2D (int matriz[3][3])
- Tamanho fixo conhecido em tempo de compilação
- Necessidade de memória contígua
- Código com foco em performance
int**
- Necessidade de dimensionamento dinâmico
- Arrays irregulares (linhas de tamanhos diferentes)
- Alocação de memória em tempo de execução
Considerações Finais
- Ponteiros são ferramentas poderosas em C++
- Permitem manipulação eficiente de memória
- Requerem cuidado para evitar erros e vazamentos de memória
- Compreender os operadores * e & é fundamental
- Endereços hexadecimais são comuns ao trabalhar com ponteiros
- Ponteiros para ponteiros ampliam as possibilidades de manipulação de dados