Alocação de Arrays Multidimensionais

por Fabio A. Mazzarino

Na linguagem C os arrays multidimensionais, ou matrizes, são alocadas como um único bloco de memória, independente de quantas dimensões tenha o array. Isso implica em algumas situações que pode facilitar o acesso a elementos individuais de forma mais rápida. Saber como os arrays funcionam auxiliam não só na otimização do código, como também na identificação e correção de falhas.

O cálculo do índice de uma matriz multidimensional segue a fórmula:

idx = idx(n) + idx(n-1) * size(n) + idx(n-2) * size(n) * size(n-1) + …

Ou seja, em uma matriz 3×3, sendo o primeiro índice x, e o segundo índice y o índice é calculado assim:

idx = y + 3 * x

Vamos fazer alguns testes com uma matriz 3×3:

#include <stdio.h>
int main() {
    int matrix[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    for (int x = 0; x < 3; x++)
        for (int y = 0; y < 3; y++)
            printf("%d ", matrix[x][y]);
    printf("\n");
    for (int ct = 0; ct < 3 * 3; ct++)
        printf("%d ", matrix[0][ct]);
    printf("\n");
    for (int ct = 0, *p = matrix; ct < 3 * 3; ct++, p++)
        printf("%d ", *p);
    printf("\n");
}

O programa acima vai entregar a seguinte saída:

0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8

Note o primeiro loop, acessando a matriz tal qual todas as demais linguagens. No segundo loop fazemos uso da falta de validação de limite de array, em conjunto com o conhecimento da forma com que os índices são calculados para acessar todos os elementos da matriz. E no último loop acessamos diretamente a memória, como se fosse um array unidimensional.

E podemos continuar usando esse conhecimento para facilitar a codificação. Podemos inicializar uma matriz 10×10 rapidamente, sem loop. Note o memset que inicializa a matriz sem loop. Na sequência vamos preencher a matriz com valores sequenciais, dessa vez com loop, mas sem indexar utilizando o operador [ ].

#include <stdio.h>
#include <string.h>
int main() {
    int matrix[10][10];
    memset(matrix, 0, sizeof(matrix));
    printf("%d %d %d\n", matrix[2][8], matrix[8][5], matrix[9][9]);
    for (int ct = 0, *p = matrix; ct < 10 * 10; ct++, p++)
        *p = ct;
    printf("%d %d %d\n", matrix[2][8], matrix[8][5], matrix[9][9]);
}

Entrega a saída:

0 0 0
28 85 99

Note como foi simples inicializar a matriz com 0, utilizando memset, ou com valores sequenciais utilizando um único loop for. Os valores obtidos no segundo loop são exatamente o resultado do cálculo do índice de memória para acessar a matriz: 2×10 + 8 = 28, 8×10 + 5 = 85 e 9×10 + 9 = 99.

Apesar de muitos times de desenvolvimento não aceitar esse tipo de acesso a matrizes, é importante conhecer a forma com que as matrizes são organizadas na memória para facilitar a depuração de problemas que possam ser encontrados.