C++: Ponteiros e Arrays

Última atualização: 2026-08-26

Na Aula 16, aprendemos sobre arrays, mas não discutimos o que um nome de array realmente é.

Na verdade, um nome de array é um ponteiro — ele armazena o endereço do primeiro elemento do array.

Entender isso ajuda a explicar por que arrays "decaem para ponteiros" quando passados como parâmetros.



1. O Nome do Array é um Ponteiro

(1) 1.1 O Fato Básico

Um nome de array é um ponteiro para o primeiro elemento.

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 
 std::cout << "arr = " << arr << std::endl;
 std::cout << "&arr[0] = " << &arr[0] << std::endl;
 // Ambos exibem o mesmo! Porque arr é &arr[0]
 
 return 0;
}

Saída (exemplo):

TEXT 📖 Somente leitura
arr = 0x7ffd4a3b
&arr[0] = 0x7ffd4a3b

💡 Ponto-chave: arr e &arr[0] são o mesmo endereço.



2. Acessando Elementos do Array com Ponteiros

(1) 2.1 Uso Básico

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p = arr; // p aponta para o primeiro elemento
 
 // Método 1: Subscrito(mesmo que array)
 std::cout << "arr[0] = " << p[0] << std::endl; // 10
 std::cout << "arr[1] = " << p[1] << std::endl; // 20
 
 // Método 2: Desreferência
 std::cout << "*p = " << *p << std::endl; // 10
 std::cout << "*(p+1) = " << *(p+1) << std::endl; // 20
 
 return 0;
}

💡 Ponto-chave: p[i] é na verdade *(p+i) (aritmética de ponteiros será explicada mais tarde).



3. Aritmética de Ponteiros

(1) 3.1 Adição/Subtração de Inteiros a Ponteiros

Ao adicionar ou subtrair um inteiro de um ponteiro, não se simplesmente adiciona/subtrai o valor do endereço — adiciona/subtrai inteiro × sizeof(tipo) bytes.

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p = arr; // Apontando para arr[0]
 
 std::cout << "p = " << p << std::endl; // Assume 0x1000
 std::cout << "p + 1 = " << p + 1 << std::endl; // 0x1004(Não 0x1001!)
 std::cout << "p + 2 = " << p + 2 << std::endl; // 0x1008
 
 return 0;
}

Como funciona:


(2) 3.2 Subtração de Ponteiros

Subtrair dois ponteiros retorna a distância entre eles (número de elementos), não o número de bytes.

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p1 = &arr[0]; // Apontando para arr[0]
 int* p2 = &arr[3]; // Apontando para arr[3]
 
 std::cout << "p2 - p1 = " << p2 - p1 << std::endl; // 3(Número de elementos)
 
 return 0;
}

💡 Ponto-chave: Subtrair ponteiros só faz sentido quando eles apontam para elementos do mesmo array.



4. Percorrendo um Array com Ponteiros (Três Métodos)

▶ Exemplo 1: Percorrendo um Array (Dificuldade ⭐)

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 
 // Método 1: Subscrito(Mais comum)
 std::cout << "Método 1: Subscrito" << std::endl;
 for (int i = 0; i < 5; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
 
 // Método 2: Aritmética de ponteiros
 std::cout << "Método 2: Aritmética de ponteiros" << std::endl;
 for (int* p = arr; p < arr + 5; p++) {
 std::cout << *p << " ";
 }
 std::cout << std::endl;
 
 // Método 3: Usar função da biblioteca padrão (aprenderemos mais tarde)
 // std::cout << "Método 3: std::begin/end" << std::endl;
 // for (int* p = std::begin(arr); p != std::end(arr); p++) {
 // std::cout << *p << " ";
 // }
 
 return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Método 1: Subscrito
10 20 30 40 50 
Método 2: Aritmética de ponteiros
10 20 30 40 50 

💡 Recomendação: O Método 1 (subscrito) é o mais intuitivo — prefira-o. O Método 2 (aritmética de ponteiros) é comum em código de baixo nível.



5. Decaimento do Array Quando Passado como Parâmetro

(1) 5.1 O Problema: Arrays Decaem para Ponteiros

Quando você passa um array para uma função, ele decai para um ponteiro (perdendo informação de tamanho).

CPP
#include <iostream>

void printSize(int arr[]) {
 // arr é na verdade um ponteiro, não um array!
 std::cout << "sizeof(arr) = " << sizeof(arr) << std::endl; // 8(sistema de 64 bits, tamanho do ponteiro)
}

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 
 std::cout << "sizeof(arr) = " << sizeof(arr) << std::endl; // 20(5 x 4 = 20 bytes)
 printSize(arr);
 
 return 0;
}

💡 Ponto-chave: Dentro da função printSize, arr é na verdade um ponteiro, então sizeof(arr) retorna o tamanho do ponteiro (8 bytes), não o tamanho do array (20 bytes).


(2) 5.2 Solução: Passar o Tamanho do Array

CPP
#include <iostream>

// Deve additionally passar o tamanho do array
void printArray(int arr[], int size) {
 for (int i = 0; i < size; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
}

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 printArray(arr, 5); // Passa nome do array (que é endereço do primeiro elemento)
 return 0;
}

💡 Dica: Depois você aprenderá std::array e std::vector, que preservam informação de tamanho e são mais seguros.



6. Prática: Invertendo um Array

▶ Exemplo 2: Invertendo um Array com Ponteiros (Dificuldade ⭐⭐)

CPP
#include <iostream>

void reverseArray(int* arr, int size) {
 int* left = arr; // Apontando para o primeiro elemento
 int* right = arr + size - 1; // Apontando para o último elemento
 
 while (left < right) {
 // Troca os valores apontados por left e right
 int temp = *left;
 *left = *right;
 *right = temp;
 
 left++; // Move para a direita
 right--; // Move para a esquerda
 }
}

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 
 std::cout << "Antes da inversão: ";
 for (int i = 0; i < 5; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
 
 reverseArray(arr, 5);
 
 std::cout << "Depois da inversão: ";
 for (int i = 0; i < 5; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
 
 return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Antes da inversão: 10 20 30 40 50 
Depois da inversão: 50 40 30 20 10 


7. Erros Comuns

(1) 7.1 Ponteiro Fora dos Limites

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p = arr;
 
 std::cout << *(p + 10) << std::endl; // ❌ Fora dos limites! p+10 aponta fora do array
 // Exibe valor lixo, ou o programa falha
 
 return 0;
}

💡 Dica: C++ não verifica automaticamente os limites de ponteiros! Isso é uma razão pela qual C++ é rápido, mas também uma fonte comum de bugs.


(2) 7.2 Subtração de Ponteiros Sem Sentido

CPP
#include <iostream>

int main() {
 int x = 5;
 int y = 10;
 int* p1 = &x;
 int* p2 = &y;
 
 std::cout << p2 - p1 << std::endl; // ❌ Comportamento indefinido! p1 e p2 apontam para arrays diferentes
 // Só subtrair ponteiros do mesmo array faz sentido
 
 return 0;
}

❓ Perguntas Frequentes

P: Por que arr e &arr têm o mesmo valor mas tipos diferentes? R:> - arr tem tipo int* (ponteiro para int) > - &arr tem tipo int(*)[5] (ponteiro para "array de 5 ints")

Então seus valores (endereços) são iguais, mas seus tipos diferem, o que significa que os passos da aritmética de ponteiros são diferentes:

CPP
int arr[5] = {10, 20, 30, 40, 50};
int* p1 = arr; // p1 + 1 + 4 bytes
int (*p2)[5] = &arr; // p2 + 1 + 20 bytes(5 × 4)

P: Por que sizeof(arr) é 20 em main mas 8 em uma função? R: Porque em main, arr é um array; dentro de uma função, arr já decaiu para um ponteiro.

Solução: Use std::array ou std::vector (coberto mais tarde).

P: A aritmética de ponteiros pode usar * e /? R: Não! Ponteiros só podem fazer: > - Adição/subtração de inteiros (p + n, p - n) > - Subtração de dois ponteiros (p2 - p1) > - Comparação (p1 < p2)

Não pode fazer: p1 * p2, p1 / p2, p1 + p2.


▶ Exemplo 3: Percorrendo um Array com Ponteiros (Dificuldade ⭐)

CPP
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* p = arr;

    for (int i = 0; i < 5; i++) {
        std::cout << "*(p+" << i << ")=" << *(p + i) << std::endl;
    }

    return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
*(p+0)=10
*(p+1)=20
*(p+2)=30
*(p+3)=40
*(p+4)=50
💡 Dica: *(p + i) é equivalente a p[i] ou arr[i]. Adicionar/subtrair inteiros de ponteiros considera automaticamente o tamanho do tipo.



📖 Resumo

📝 Exercícios

  1. Básico (Dificuldade ⭐): Declare um array int arr[5] = {1, 2, 3, 4, 5}, depois declare um ponteiro int* p apontando para arr. Exiba todos os elementos usando o ponteiro.

  2. Intermediário (Dificuldade ⭐⭐): Escreva uma função int* findElement(int* arr, int size, int target) que procure um valor alvo em um array. Se encontrado, retorne um ponteiro para esse elemento; se não encontrado, retorne nullptr.

  3. Desafio (Dificuldade ⭐⭐⭐): Escreva um programa que implemente "bubble sort" usando ponteiros:

  4. Percorra o array, comparando elementos adjacentes

  5. Se estiverem na ordem errada, troque-os

  6. Repita esse processo até que o array esteja ordenado


8. 🚀 Próximo Passo

Agora que você aprendeu sobre ponteiros e arrays, vamos avançar para Aritmética Avançada de Ponteiros (Aula 24) — uma visão mais profunda de tipos de ponteiros, ponteiros void*, e ponteiros multinível.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%