🔗 Ponteiros e Arrays · Relação e Aritmética · C/C++

🔗 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çãoSignificado
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...

Postar um comentário

0 Comentários