🔗 Ponteiros e Arrays
"Em C/C++, ponteiros e arrays estão intimamente ligados. O nome de um array é essencialmente um ponteiro constante para seu primeiro elemento, e a notação de colchetes é açúcar sintático para aritmética de ponteiros."
Compreender a relação entre ponteiros e arrays é fundamental para programar em C/C++. Essa ligação explica por que arrays são passados por referência para funções, como strings funcionam e como alocar estruturas de dados dinâmicas.
📌 O Nome do Array como Ponteiro
Quando você declara um array, seu nome pode ser usado como um ponteiro constante para o primeiro elemento.
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr; // Equivalente a: int* p = &arr[0];
cout << *p << endl; // 10 (arr[0])
cout << *(p + 1) << endl; // 20 (arr[1])
cout << *(p + 2) << endl; // 30 (arr[2])
// O nome do array também funciona como ponteiro
cout << *arr << endl; // 10
cout << *(arr + 3) << endl; // 40
⚠️ Diferença Crucial: O nome do array é um
ponteiro constante. Você não pode modificá-lo para apontar para outro lugar.
int arr[5];
int* p = arr;
p++; // OK: p agora aponta para arr[1]
// arr++; // ERRO: arr é constante, não pode ser alterado
📝 Notação de Colchetes e Aritmética de Ponteiros
A notação arr[i] é exatamente equivalente a *(arr + i). O compilador traduz a primeira para a segunda.
int arr[5] = {1, 2, 3, 4, 5};
// Estas duas linhas são IDÊNTICAS para o compilador
cout << arr[2] << endl; // 3
cout << *(arr + 2) << endl; // 3
// Curiosidade: devido à comutatividade da adição...
cout << 2[arr] << endl; // 3! (equivalente a *(2 + arr))
// (Não use isso em código real — é apenas uma curiosidade)
🔄 Percorrendo Arrays com Ponteiros
Ponteiros oferecem uma forma alternativa e muitas vezes mais expressiva de iterar sobre arrays.
int arr[5] = {10, 20, 30, 40, 50};
// Método 1: Índices (tradicional)
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
// Método 2: Aritmética de ponteiros (base fixa)
for (int i = 0; i < 5; i++) {
cout << *(arr + i) << " ";
}
// Método 3: Ponteiro móvel (mais eficiente em alguns contextos)
for (int* p = arr; p < arr + 5; p++) {
cout << *p << " ";
}
// Método 4: Range-based for (C++11) — mais moderno e seguro
for (int x : arr) {
cout << x << " ";
}
📤 Arrays como Parâmetros de Funções
Quando um array é passado para uma função, ele decai para um ponteiro. O tamanho do array original é perdido.
// Estas três declarações são EQUIVALENTES
void funcao1(int arr[]);
void funcao2(int arr[10]); // O 10 é IGNORADO!
void funcao3(int* arr);
// É por isso que geralmente passamos o tamanho separadamente
void imprimirArray(int* arr, int tamanho) {
for (int i = 0; i < tamanho; i++) {
cout << arr[i] << " ";
}
}
int main() {
int numeros[5] = {1, 2, 3, 4, 5};
imprimirArray(numeros, 5); // Passa o ponteiro e o tamanho
}
💡 sizeof dentro de funções: Dentro de uma função que recebe um array como parâmetro, sizeof(arr) retorna o tamanho do ponteiro (4 ou 8 bytes), não do array original. Nunca confie em sizeof para obter o tamanho de um array dentro de uma função!
🧵 Ponteiros e Strings (C-style)
Strings em C são arrays de caracteres terminados por \0. Ponteiros para char são a forma padrão de manipulá-las.
// String literal: ponteiro para área de memória somente leitura
const char* msg = "Olá, mundo!";
// Array de caracteres: modificável
char nome[] = "João";
nome[0] = 'L'; // OK: "Loão"
// Percorrendo string com ponteiro
const char* p = msg;
while (*p != '\0') {
cout << *p;
p++;
}
// Saída: Olá, mundo!
// Funções da biblioteca padrão (cstring)
#include <cstring>
cout << strlen(msg) << endl; // 11 (comprimento)
cout << strcmp("abc", "abd") << endl; // -1 (comparação)
📊 Array de Ponteiros vs. Ponteiro para Array
A sintaxe pode ser confusa. A tabela abaixo esclarece as diferenças.
| Declaração | Significado |
int* arr[5] | Array de 5 ponteiros para inteiros |
int (*ptr)[5] | Ponteiro para um array de 5 inteiros |
int* (*ptr)[5] | Ponteiro para um array de 5 ponteiros para inteiros |
// Array de ponteiros (comum para matrizes esparsas ou listas)
int* linhas[3];
linhas[0] = new int[2]{1, 2};
linhas[1] = new int[3]{3, 4, 5};
linhas[2] = new int[4]{6, 7, 8, 9};
// Ponteiro para array (útil para arrays bidimensionais alocados dinamicamente)
int (*matriz)[3] = new int[2][3];
matriz[0][0] = 1;
matriz[1][2] = 6;
delete[] matriz;
📏 Tamanho de Arrays vs. Ponteiros
É crucial entender a diferença de tamanho entre arrays e ponteiros.
int arr[10];
int* p = arr;
cout << sizeof(arr) << endl; // 40 (10 * 4 bytes, assumindo int de 4 bytes)
cout << sizeof(p) << endl; // 8 (tamanho do ponteiro em 64 bits)
// Número de elementos do array
cout << sizeof(arr) / sizeof(arr[0]) << endl; // 10
🔗 Conclusão
A relação entre ponteiros e arrays é profunda e fundamental em C/C++. Entender que o nome do array é um ponteiro constante, que a notação de colchetes é açúcar sintático para aritmética de ponteiros e que arrays decaem para ponteiros em funções é essencial para escrever código correto e eficiente. Esse conhecimento é a base para manipular strings, alocar estruturas dinâmicas e compreender código de baixo nível.
⏭️ Próximo: Usando new e delete com arrays...
0 Comentários