Arrays multidimensionais
Esta aula aborda arrays multidimensionais em C, com foco em matrizes, acesso a elementos, organização na memória (row-major) e passagem para funções. Inclui exemplos práticos e exercícios para fixação.
Arrays multidimensionais em C permitem armazenar dados em estruturas com duas ou mais dimensões, como tabelas (linhas e colunas). Eles são amplamente utilizados em computação gráfica, simulações e processamento de dados. Nesta aula, vamos explorar como declarar, acessar e manipular esses arrays, além de entender como eles são organizados na memória e como passá-los para funções.
Dominar arrays multidimensionais é essencial para trabalhar com dados tabulares e matrizes em problemas científicos e de engenharia. Veremos desde conceitos básicos até técnicas avançadas de passagem para funções.
Matrizes
Uma matriz é um array bidimensional, ou seja, um array de arrays. Em C, declaramos uma matriz especificando o número de linhas e colunas entre colchetes. Por exemplo, int matriz[3][4]; cria uma matriz com 3 linhas e 4 colunas, totalizando 12 elementos do tipo int.
A inicialização pode ser feita na declaração, usando chaves aninhadas. Exemplo: int mat[2][3] = {{1,2,3}, {4,5,6}}; atribui valores linha por linha. Se houver menos valores que o tamanho, os elementos restantes são inicializados com zero.
#include <stdio.h>
int main() {
int matriz[2][3] = {{1, 2, 3}, {4, 5, 6}};
// Acessando e imprimindo
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matriz[i][j]);
}
printf("\n");
}
return 0;
}É possível declarar arrays com mais de duas dimensões, como int cubo[3][4][5]; (3 faces, 4 linhas, 5 colunas). O padrão é similar: cada dimensão adicional adiciona um nível de aninhamento.
Acesso
Para acessar um elemento de uma matriz, usamos índices separados por colchetes: matriz[linha][coluna]. Os índices começam em 0. No exemplo anterior, matriz[1][2] acessa o elemento da segunda linha (índice 1) e terceira coluna (índice 2), que é 6.
É importante não ultrapassar os limites da matriz, pois C não faz verificação de limites, podendo causar comportamentos indefinidos. O acesso é feito por aritmética de ponteiros: matriz[i][j] é equivalente a *(*(matriz + i) + j).
#include <stdio.h>
int main() {
int mat[2][3] = {{10, 20, 30}, {40, 50, 60}};
int *ptr = &mat[0][0];
printf("Elemento [1][2] via índice: %d\n", mat[1][2]);
printf("Elemento [1][2] via ponteiro: %d\n", *(ptr + 1*3 + 2));
return 0;
}Note que o cálculo do deslocamento usa o número de colunas (3) porque a memória é organizada em ordem row-major.
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 consecutivamente na memória. Por exemplo, uma matriz 2×3 é armazenada como: [0][0], [0][1], [0][2], [1][0], [1][1], [1][2].
Isso significa que a última dimensão varia mais rapidamente. Conhecer a organização é útil para otimizar loops: percorrer os elementos na ordem de armazenamento melhora a localidade de referência e o desempenho.
#include <stdio.h>
int main() {
int mat[2][3] = {{1,2,3}, {4,5,6}};
int *p = &mat[0][0];
printf("Endereços (row-major):\n");
for (int i = 0; i < 2*3; i++) {
printf("%p: %d\n", (void*)&p[i], p[i]);
}
return 0;
}Isso contrasta com linguagens como Fortran, que usam column-major. Em C, loops aninhados com o índice da coluna no loop interno são mais eficientes.
Passagem para funções
Passar arrays multidimensionais para funções requer cuidado. O parâmetro deve especificar o número de colunas (a segunda dimensão) porque o compilador precisa saber o tamanho de cada linha para calcular endereços. A primeira dimensão pode ser omitida.
#include <stdio.h>
void imprimirMatriz(int linhas, int colunas, int mat[][colunas]) {
for (int i = 0; i < linhas; i++) {
for (int j = 0; j < colunas; j++) {
printf("%d ", mat[i][j]);
}
printf("\n");
}
}
int main() {
int mat[2][3] = {{1,2,3}, {4,5,6}};
imprimirMatriz(2, 3, mat);
return 0;
}Outra forma é usar ponteiro para array de tamanho fixo: void func(int (*mat)[3]). Isso só funciona se o número de colunas for conhecido em tempo de compilação.
Para arrays com mais de duas dimensões, é necessário especificar todas as dimensões, exceto a primeira. Exemplo: void func(int arr[][4][5]).
Boas práticas
- Sempre verifique os limites dos índices para evitar estouro de buffer.
- Prefira loops aninhados com o índice da coluna no loop interno para melhor desempenho devido à localidade de referência.
- Ao passar para funções, use VLA (Variable Length Arrays) como parâmetro, disponível a partir do C99, para maior flexibilidade.
- Evite arrays multidimensionais muito grandes na pilha (stack); prefira alocação dinâmica.
Referências
- cppreference: Array declaration
- GNU C Manual: Arrays
- Learn-C.org: Multidimensional Arrays
- Wikipedia: Row- and column-major order
- Tutorialspoint: C Multidimensional Arrays
Exercícios
- Declare uma matriz 3x3 de inteiros chamada
identidadee inicialize-a como uma matriz identidade (1 na diagonal principal, 0 nos demais). Em seguida, imprima a matriz. - Escreva uma função
somaMatrizesque recebe duas matrizes 2x3 e retorna a soma (elemento a elemento) em uma terceira matriz. Teste no main. - Explique por que o loop abaixo é ineficiente para uma matriz 1000x1000 e reescreva-o de forma otimizada. Código original:
for(j=0; j<1000; j++) for(i=0; i<1000; i++) mat[i][j] = 0; - Dada a declaração
int arr[3][4] = {0};, escreva uma expressão usando aritmética de ponteiros que acesse o elemento na linha 2, coluna 3. - Crie um array tridimensional de inteiros com dimensões 2x3x4, inicialize todos os elementos com o valor 1 e imprima todos os elementos.
#include <stdio.h>
int main() {
int identidade[3][3] = {{1,0,0}, {0,1,0}, {0,0,1}};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", identidade[i][j]);
}
printf("\n");
}
return 0;
}#include <stdio.h>
void somaMatrizes(int a[][3], int b[][3], int resultado[][3], int linhas) {
for (int i = 0; i < linhas; i++) {
for (int j = 0; j < 3; j++) {
resultado[i][j] = a[i][j] + b[i][j];
}
}
}
int main() {
int A[2][3] = {{1,2,3}, {4,5,6}};
int B[2][3] = {{7,8,9}, {10,11,12}};
int C[2][3];
somaMatrizes(A, B, C, 2);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", C[i][j]);
}
printf("\n");
}
return 0;
}for(i=0; i<1000; i++) for(j=0; j<1000; j++) mat[i][j] = 0;*(*(arr + 2) + 3) ou *(&arr[0][0] + 2*4 + 3).#include <stdio.h>
int main() {
int arr[2][3][4];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
arr[i][j][k] = 1;
}
}
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
printf("%d ", arr[i][j][k]);
}
printf("\n");
}
printf("\n");
}
return 0;
}