Arrays multidimensionais
Esta aula aborda arrays multidimensionais em C, incluindo declaração e inicialização de matrizes, acesso a elementos, organização na memória no formato row-major e passagem de arrays multidimensionais para funções. O conteúdo é prático e progressivo, com exemplos de código e exercícios.
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
- cppreference: Array declaration
- Learn-C.org: Multidimensional Arrays
- GeeksforGeeks: Multidimensional Arrays in C
- Wikipedia: Row- and column-major order
- Stack Overflow: Passing a multidimensional array to a function in C
Exercícios
- Declare uma matriz 4x5 de inteiros chamada
mate inicialize-a com zeros. Em seguida, preencha a diagonal principal (elementos onde linha == coluna) com o valor 1. Imprima a matriz. - Escreva uma função
soma_matrizesque recebe duas matrizes 3x3 e armazena a soma em uma terceira matriz. Use a função nomainpara somar duas matrizes e imprimir o resultado. - Dada a matriz
int m[2][3] = {{1,2,3},{4,5,6}}, calcule manualmente o endereço dem[0][2]em[1][1]sabendo que o endereço base é 1000 e cada int ocupa 4 bytes. Verifique com um programa que imprime os endereços. - Crie uma função que recebe uma matriz 4x4 e retorna o maior elemento. Teste com uma matriz de exemplo.
- 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.
#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;
}
#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;
}
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;
}
#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;
}
#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;
}