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++

Código 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 = &num;     // 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