Arrays multidimensionais são uma extensão natural dos arrays unidimensionais e permitem armazenar dados em estruturas com duas ou mais dimensões, como tabelas, matrizes ou cubos. Em C, um array bidimensional é declarado como tipo nome[linhas][colunas] e é armazenado em memória de forma contígua, linha por linha (row-major order).

Nesta aula, vamos explorar como declarar, inicializar, acessar e manipular arrays multidimensionais. Também veremos como passá-los para funções, considerando que o compilador precisa saber o número de colunas (ou dimensões internas) para calcular corretamente os endereços.

Matrizes

Uma matriz é um array bidimensional, ou seja, uma coleção de elementos do mesmo tipo organizados em linhas e colunas. A declaração segue o formato tipo nome[linhas][colunas]. Por exemplo, int mat[3][4] declara uma matriz de 3 linhas e 4 colunas, totalizando 12 elementos do tipo int.

A inicialização pode ser feita no momento da declaração, usando chaves aninhadas. Cada par de chaves internas representa uma linha. Se houver menos elementos do que o tamanho da linha, os demais são preenchidos com zero. Exemplo:

int matriz[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

Também é possível inicializar um array multidimensional sem especificar o número de linhas, desde que o número de colunas seja fornecido. O compilador deduz o número de linhas a partir da lista de inicializadores:

int mat[][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; // 3 linhas, 3 colunas

Arrays de três ou mais dimensões seguem a mesma lógica: int cubo[2][3][4] representa 2 camadas, cada uma com 3 linhas e 4 colunas.

Acesso

O acesso a um elemento de um array multidimensional é feito usando índices separados por colchetes. Lembre-se de que os índices em C começam em 0. Para a matriz int mat[3][4], o elemento na linha i e coluna j é acessado como mat[i][j].

Exemplo de preenchimento e impressão de uma matriz 3x4:

#include <stdio.h>

int main() {
    int mat[3][4];
    int valor = 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            mat[i][j] = valor++;
        }
    }
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%2d ", mat[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Saída:

 0  1  2  3
 4  5  6  7
 8  9 10 11

O acesso é feito na forma matriz[linha][coluna]. É importante não confundir a ordem: primeiro a linha, depois a coluna.

Memória (row-major)

Em C, arrays multidimensionais são armazenados em ordem row-major, ou seja, os elementos de cada linha são armazenados de forma contígua na memória, e as linhas são colocadas uma após a outra. Por exemplo, a matriz int m[2][3] com valores {{1,2,3},{4,5,6}} é armazenada como: 1,2,3,4,5,6.

Isso significa que o endereço de um elemento m[i][j] pode ser calculado como: endereço_base + (i * numero_de_colunas + j) * tamanho_do_tipo. Essa organização é importante para otimização de cache e para passagem para funções.

Exemplo que demonstra a disposição na memória:

#include <stdio.h>

int main() {
    int m[2][3] = {{1,2,3},{4,5,6}};
    int *p = &m[0][0];
    for (int k = 0; k < 6; k++) {
        printf("%d ", p[k]);
    }
    printf("\n");
    // Acessando como se fosse unidimensional
    printf("m[1][2] = %d, p[1*3+2] = %d\n", m[1][2], p[1*3+2]);
    return 0;
}

Saída:

1 2 3 4 5 6
m[1][2] = 6, p[1*3+2] = 6

Essa característica permite tratar um array multidimensional como um array unidimensional de tamanho total, se necessário.

Passagem para funções

Passar um array multidimensional para uma função requer cuidado, pois o compilador precisa saber o tamanho de todas as dimensões, exceto a primeira. A forma mais comum é especificar o número de colunas (ou as dimensões internas) no parâmetro. Por exemplo:

void imprime_matriz(int mat[][4], int linhas) {
    for (int i = 0; i < linhas; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

Aqui, int mat[][4] indica que a matriz tem um número desconhecido de linhas, mas cada linha tem exatamente 4 colunas. O número de linhas é passado como parâmetro separado.

Outra forma é usar um ponteiro para array de tamanho fixo: void funcao(int (*mat)[4], int linhas). Isso é equivalente à sintaxe anterior. Exemplo completo:

#include <stdio.h>

void soma_um(int mat[][3], int linhas) {
    for (int i = 0; i < linhas; i++) {
        for (int j = 0; j < 3; j++) {
            mat[i][j] += 1;
        }
    }
}

int main() {
    int m[2][3] = {{1,2,3},{4,5,6}};
    soma_um(m, 2);
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", m[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Saída:

2 3 4
5 6 7

Para arrays de dimensão maior, basta especificar todas as dimensões internas. Por exemplo, void func(int arr[][4][5], int camadas).

Uma abordagem alternativa é passar um ponteiro simples e as dimensões, mas isso exige calcular o índice manualmente. Não é recomendado para código legível, mas é possível:

void imprime_plano(int *arr, int linhas, int colunas) {
    for (int i = 0; i < linhas; i++) {
        for (int j = 0; j < colunas; j++) {
            printf("%d ", arr[i * colunas + j]);
        }
        printf("\n");
    }
}
// chamada: imprime_plano(&m[0][0], 2, 3);

Boas práticas

  • Preferir a sintaxe tipo nome[][colunas] para funções, pois é mais clara.
  • Evite declarar arrays multidimensionais muito grandes na pilha (stack); use alocação dinâmica se necessário.
  • Lembre-se de que o índice da linha vem primeiro, depois coluna.
  • Use constantes simbólicas para as dimensões, facilitando manutenção.

Referências

Exercícios

  1. Declare uma matriz 4x5 de inteiros chamada mat e inicialize-a com zeros. Em seguida, preencha a diagonal principal (elementos onde linha == coluna) com o valor 1. Imprima a matriz.
  2. ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int mat[4][5] = {0}; // inicializa com zeros
        for (int i = 0; i < 4; i++) {
            mat[i][i] = 1;
        }
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 5; j++) {
                printf("%d ", mat[i][j]);
            }
            printf("\n");
        }
        return 0;
    }
  3. Escreva uma função soma_matrizes que recebe duas matrizes 3x3 e armazena a soma em uma terceira matriz. Use a função no main para somar duas matrizes e imprimir o resultado.
  4. ✓ Resposta:
    #include <stdio.h>
    
    void soma_matrizes(int a[][3], int b[][3], int c[][3]) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                c[i][j] = a[i][j] + b[i][j];
            }
        }
    }
    
    int main() {
        int A[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
        int B[3][3] = {{9,8,7},{6,5,4},{3,2,1}};
        int C[3][3];
        soma_matrizes(A, B, C);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                printf("%3d ", C[i][j]);
            }
            printf("\n");
        }
        return 0;
    }
  5. Dada a matriz int m[2][3] = {{1,2,3},{4,5,6}}, calcule manualmente o endereço de m[0][2] e m[1][1] sabendo que o endereço base é 1000 e cada int ocupa 4 bytes. Verifique com um programa que imprime os endereços.
  6. ✓ Resposta:

    Endereço de m[0][2] = 1000 + (0*3 + 2)*4 = 1000 + 8 = 1008.
    Endereço de m[1][1] = 1000 + (1*3 + 1)*4 = 1000 + 16 = 1016.

    #include <stdio.h>
    
    int main() {
        int m[2][3] = {{1,2,3},{4,5,6}};
        printf("Endereco de m[0][2]: %p\n", (void*)&m[0][2]);
        printf("Endereco de m[1][1]: %p\n", (void*)&m[1][1]);
        printf("Diferenca: %ld bytes\n", (long)(&m[1][1] - &m[0][2]) * sizeof(int));
        return 0;
    }
  7. Crie uma função que recebe uma matriz 4x4 e retorna o maior elemento. Teste com uma matriz de exemplo.
  8. ✓ Resposta:
    #include <stdio.h>
    
    int maior_matriz(int mat[][4], int linhas) {
        int maior = mat[0][0];
        for (int i = 0; i < linhas; i++) {
            for (int j = 0; j < 4; j++) {
                if (mat[i][j] > maior) maior = mat[i][j];
            }
        }
        return maior;
    }
    
    int main() {
        int m[4][4] = {
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,16}
        };
        printf("Maior elemento: %d\n", maior_matriz(m, 4));
        return 0;
    }
  9. Declare um array tridimensional int cubo[2][3][4] e inicialize-o com valores sequenciais (0 a 23). Em seguida, imprima os valores de cada camada (primeira dimensão) como uma matriz 3x4.
  10. ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int cubo[2][3][4];
        int valor = 0;
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 3; j++) {
                for (int k = 0; k < 4; k++) {
                    cubo[i][j][k] = valor++;
                }
            }
        }
        for (int i = 0; i < 2; i++) {
            printf("Camada %d:\n", i);
            for (int j = 0; j < 3; j++) {
                for (int k = 0; k < 4; k++) {
                    printf("%2d ", cubo[i][j][k]);
                }
                printf("\n");
            }
            printf("\n");
        }
        return 0;
    }