Layout row-major, passagem para funções, alocação dinâmica, exemplos com matrizes e imagens. Continua a aula básica de arrays.
int a[3][4] é na verdade só 12 ints contíguos. A parte "2D" é como você pensa neles.
// 3 linhas x 4 colunas int m[3][4] = { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 12} }; printf("%d\n", m[1][2]); // → 7 (linha 1, coluna 2, indexado a partir de 0)
// 2 camadas x 3 linhas x 4 colunas int cube[2][3][4]; for (int l = 0; l < 2; l++) for (int i = 0; i < 3; i++) for (int j = 0; j < 4; j++) cube[l][i][j] = l * 100 + i * 10 + j;
int m[3][4] = {0}; preenche tudo com zero. Com int m[][4] = {{1,2,3,4},{5,6,7,8}};, só o tamanho externo pode ser omitido — a contagem de colunas ainda é obrigatória.int m[3][4]; sizeof(m) // 48 (3 * 4 * 4 bytes) sizeof(m[0]) // 16 (uma linha = 4 * 4 bytes) sizeof(m[0][0]) // 4 (um int) // rows = sizeof(m) / sizeof(m[0]) // cols = sizeof(m[0]) / sizeof(m[0][0])
int *p = (int *)m; p[i*COLS + j]
// Percorre um array 2D como se fosse 1D int m[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p = (int *)m; for (int k = 0; k < 12; k++) printf("%d ", p[k]); // → 1 2 3 4 5 6 7 8 9 10 11 12
// contagem de colunas eh obrigatoria; linhas pode ser omitido void print_34(int m[][4], int rows) { for (int i = 0; i < rows; i++) for (int j = 0; j < 4; j++) printf("%d ", m[i][j]); } int a[3][4]; print_34(a, 3);
// Declare linhas/colunas primeiro, depois aceite o array VLA void print_any(int rows, int cols, int m[rows][cols]) { for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) printf("%d ", m[i][j]); } int a[3][4], b[2][5]; print_any(3, 4, a); print_any(2, 5, b);
m[i][j]. Contras: requer C99+; MSVC mais antigo não suporta VLAs.// "Achate" para 1D e calcule o indice voce mesmo. void print_flat(int *m, int rows, int cols) { for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) printf("%d ", m[i * cols + j]); } int a[3][4]; print_flat((int *)a, 3, 4);
m[i][j].// Passa um array de ponteiros de linha. void print_pp(int **m, int rows, int cols) { for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) printf("%d ", m[i][j]); } // O chamador precisa montar um array de ponteiros de linha primeiro. int row0[] = {1,2,3}; int row1[] = {4,5,6}; int *rows[] = {row0, row1}; print_pp(rows, 2, 3);
int a[3][4] para int ** NÃO funciona. Seus layouts de memória são completamente diferentes — um é um bloco de ints, o outro é um array de ponteiros. Essa é a maior fonte de confusão com arrays multidimensionais.#include <stdio.h> #include <stdlib.h> int main(void) { int rows = 3, cols = 4; // aloca todos os elementos num unico bloco int *m = malloc(sizeof(int) * rows * cols); if (!m) return 1; // indexacao manual: m[i*cols + j] for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) m[i * cols + j] = i * 10 + j; free(m); return 0; }
// Bloco contiguo E indexacao 2D. int (*m)[cols] = malloc(sizeof(int[rows][cols])); m[1][2] = 42; // indices normais funcionam free(m);
int **m = malloc(sizeof(int *) * rows); // array de ponteiros de linha for (int i = 0; i < rows; i++) m[i] = malloc(sizeof(int) * cols); // uma linha cada m[1][2] = 42; // sintaxe m[i][j] funciona // libere em ordem reversa for (int i = 0; i < rows; i++) free(m[i]); free(m);
rows + 1 chamadas a malloc (mais lento e fragmenta memória), e as linhas acabam espalhadas na RAM (pior comportamento de cache). Prefira o Padrão A a menos que você realmente precise da estrutura irregular.C[i][j] = Σ A[i][l] * B[l][j].#include <stdio.h> #define M 2 #define K 3 #define N 2 void matmul(int A[M][K], int B[K][N], int C[M][N]) { for (int i = 0; i < M; i++) for (int j = 0; j < N; j++) { int sum = 0; for (int l = 0; l < K; l++) sum += A[i][l] * B[l][j]; C[i][j] = sum; } } int main(void) { int A[M][K] = {{1,2,3},{4,5,6}}; int B[K][N] = {{7,8},{9,10},{11,12}}; int C[M][N]; matmul(A, B, C); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) printf("%4d", C[i][j]); putchar('\n'); } // esperado: // 58 64 // 139 154 }
ilj (acumulando l no laço mais interno) percorre B linha a linha, o que pode ser significativamente mais rápido em matrizes grandes graças ao cache row-major.#include <stdio.h> #define W 6 #define H 4 void flip_horizontal(unsigned char img[H][W]) { for (int i = 0; i < H; i++) for (int j = 0; j < W / 2; j++) { unsigned char t = img[i][j]; img[i][j] = img[i][W - 1 - j]; img[i][W - 1 - j] = t; } } int main(void) { unsigned char img[H][W] = { {10,20,30,40,50,60}, {11,21,31,41,51,61}, {12,22,32,42,52,62}, {13,23,33,43,53,63}, }; flip_horizontal(img); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) printf("%3d ", img[i][j]); putchar('\n'); } }
unsigned char img[H][W][3]. Para espelhamento vertical, troque linhas inteiras com memcpy.int B[4][3] de int A[3][4].int table[9][9] com (i+1)*(j+1) e imprima.memcpy para trocar linhas inteiras de uma vez.int trace(int n, int m[n][n]) (usando parâmetro VLA) que retorna a soma das entradas da diagonal.int(*)[N]Teste seu entendimento desta aula!
int a[3][4]; é disposto na memória?C usa layout row-major. A ordem é a[0][0], a[0][1], ..., a[0][3], a[1][0], ....
Você precisa especificar pelo menos a segunda dimensão. int ** é um array de ponteiros — um tipo diferente de um array 2D.
a[i][j]?a+i dá o endereço da linha i, +j seleciona a coluna j, e * desreferencia para o valor.