Ponteiro para Array vs. Array de Ponteiros em C

Este artigo explora a distinção e o uso de ponteiros para array e arrays de ponteiros em C, conceitos que frequentemente causam confusão.

Entendendo Ponteiros para Array

Assim como um ponteiro para inteiro (int \*p) armazena o endereço de um inteiro, um ponteiro para array armazena o endereço de um array inteiro. Para ilustrar:

  • int *p; é um ponteiro para um inteiro.
  • char *pc; é um ponteiro para um caractere.

Seguindo essa analogia, um ponteiro para array seria um ponteiro que aponta para um array. A declaração de um ponteiro para array reflete sua natureza.

Considere os seguintes exemplos:

  • int* p1 = &arr;: O tipo deste ponteiro é int *.
  • char* p2 = &arr;: O tipo deste ponteiro é char *.
  • int (*p3)[5] = &arr;: O tipo deste ponteiro é int (*)[5].

A regra geral para determinar o tipo de um ponteiro é remover o nome do array da sua declaração. Isso se assemelha à forma como determinamos o tipo de uma variável de array.

Um ponto adicional a ser notado para int arr[10];:

  • arr: Representa o endereço do primeiro elemento do array.
  • &arr[0]: Também representa o endereço do primeiro elemento.
  • &arr: Representa o endereço do array em si.

Diferenciando Pontieros para Array e Arrays de Ponteiros na Sintaxe

A distinção mais clara entre ponteiros para array e arrays de ponteiros pode ser vista em suas declarações:


// Exemplo de Array de Ponteiros
int *ptrArray[10]; // ptrArray é um array de 10 ponteiros para int

// Exemplo de Ponteiro para Array
int (*arrayPtr)[10]; // arrayPtr é um ponteiro para um array de 10 ints

A chave para diferenciar essas duas estruturas em código C está em observar a precedência dos operadores. Em int *ptrArray[10];, os colchetes [] têm maior precedência que o asterisco *. Isso significa que ptrArray é primeiramente um array (de 10 elementos), e cada elemento desse array é um ponteiro para int. Portanto, é um array de ponteiros.

Inversamente, em int (*arrayPtr)[10];, os parênteses () forçam o asterisco * a ser avaliado antes dos colchetes []. Isso indica que arrayPtr é primeiramente um ponteiro, e esse ponteiro aponta para um array de 10 ints. Portanto, é um ponteiro para um array.

Em resumo: A precedência dos operadores na declaração é o fator determinante.

No contexto de int (*arrayPtr)[10];, o asterisco dentro dos parênteses (*arrayPtr) não é um operador de desreferência, mas sim uma notação que indica que arrayPtr é um ponteiro.

Imprimindo um Array Bidimensional Usando um Ponteiro para Array

A função a seguir demonstra como um ponteiro para array pode ser usado para percorrer e imprimir os elementos de um array bidimensional:


#include <stdio.h>

void print2DArray(int (*p)[4], int rows, int cols) {
    int i, j;
    for (i = 0; i < rows; i++) {
        for (j = 0; j < cols; j++) {
            // Acessa o elemento usando aritmética de ponteiros
            printf("%d ", *(*(p + i) + j));
        }
        printf("\n");
    }
}

int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    printf("Printing using pointer to array:\n");
    print2DArray(matrix, 3, 4);

    return 0;
}

A linha crucial aqui é printf("%d ", *(*(p + i) + j));. Para entender isso, vamos compará-la com o acesso a um array unidimensional:


int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *p = arr; // p aponta para o início de arr

printf("%d", p[i]);       // Equivalente a arr[i]
printf("%d", *(p + i));   // Equivalente a arr[i]
printf("%d", *(arr + i)); // Equivalente a arr[i]
printf("%d", arr[i]);     // Acesso direto

No contexto do ponteiro para array bidimensional int (*p)[4], p + i avança o ponteiro para a i-ésima linha (cada linha tendo 4 elementos). Então, *(p + i) desreferencia para obter o início dessa linha (que é um array de 4 inteiros). Finalmente, *(*(p + i) + j) acessa o j-ésimo elemento dentro dessa linha.

Ao passar um array bidimensional para uma função em C, estamos na verdade passando o endereço do seu primeiro elemento. No caso de um array bidimensional, o primeiro elemento é a primeira linha, que é tratada como um array unidimensional.

Resumo e Exemplos Adicionais

Para consolidar o entendimento:

  • int arr[5];: Declara um array de 5 elementos, onde cada elemento é um int.
  • int *ptrArr[10];: Declara um array de 10 elementos, onde cada elemento é um ponteiro para int. ptrArr é um array de ponteiros.
  • int (*arrPtr)[10];: Declara arrPtr como um ponteiro que aponta para um array de 10 ints. arrPtr é um ponteiro para um array.
  • int (*(*arrPtrArr)[5])[10];: Esta declaração é mais complexa. Ela define um array (com 5 elementos) onde cada elemento é um ponteiro para um array de 10 ints.

Tags: C ponteiros Arrays aritmética de ponteiros programação de baixo nível

Publicado em 7-23 18:08