Aula 25 — Matrizes (Arrays 2D) em C

Tabelas de dados na memória — linhas, colunas e row-major order

1. O que é uma Matriz?

Um array unidimensional armazena uma sequência de valores — como uma fila. Uma matriz é um array de duas dimensões: linhas e colunas, como uma tabela ou planilha.

Uma matriz (ou array bidimensional) é uma coleção de elementos do mesmo tipo organizados em linhas e colunas. Em C, é declarada como tipo nome[linhas][colunas] e armazenada na memória de forma contígua em row-major order (linha por linha).

Visualização

Uma matriz int notas[3][4] representa 3 alunos com 4 notas cada:

Coluna 0 (Nota 1) Coluna 1 (Nota 2) Coluna 2 (Nota 3) Coluna 3 (Nota 4)
Linha 0 (Aluno A) notas[0][0] = 7 notas[0][1] = 8 notas[0][2] = 6 notas[0][3] = 9
Linha 1 (Aluno B) notas[1][0] = 5 notas[1][1] = 7 notas[1][2] = 8 notas[1][3] = 6
Linha 2 (Aluno C) notas[2][0] = 9 notas[2][1] = 10 notas[2][2] = 8 notas[2][3] = 7
Row-major order: C armazena todos os elementos da linha 0 primeiro, depois os da linha 1, e assim por diante. Os 12 elementos acima ficam em 12 posições consecutivas na memória: [7][8][6][9][5][7][8][6][9][10][8][7].

2. Declaração e Inicialização

Forma 1 — Declarar e preencher depois

int matriz[2][2];          // declara sem inicializar (contém lixo de memória)
matriz[0][0] = 1;
matriz[0][1] = 2;
matriz[1][0] = 3;
matriz[1][1] = 4;

Forma 2 — Inicialização por chaves aninhadas

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

Forma 3 — Inicialização linear (equivalente à 2)

int matriz[2][3] = {1, 2, 3, 4, 5, 6};  // C preenche linha por linha

Forma 4 — Inicialização parcial (restante vira 0)

int matriz[3][3] = { {1}, {4, 5} };
// Resultado:
// 1  0  0
// 4  5  0
// 0  0  0

Forma 5 — Array de caracteres (strings em tabela)

char dias[7][12] = {
    "Segunda", "Terça", "Quarta",
    "Quinta",  "Sexta", "Sábado", "Domingo"
};
printf("%s\n", dias[0]);   // imprime: Segunda
⚠️ Atenção com o tamanho: Em C, o compilador precisa saber o número de colunas para calcular endereços. Você pode omitir as linhas (int m[][3] = ...), mas nunca as colunas.

3. Acessando Matrizes com Loops Aninhados

O padrão universal para percorrer uma matriz é usar dois loops for aninhados: o externo para as linhas e o interno para as colunas.

#include <stdio.h>

int main() {
    int matriz[2][2];
    int i, j;

    // Leitura: preenche com scanf
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            printf("Digite matriz[%d][%d]: ", i, j);
            scanf("%d", &matriz[i][j]);
        }
    }

    // Impressão
    printf("\nMatriz:\n");
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            printf("%4d", matriz[i][j]);  // %4d: largura mínima 4 para alinhar
        }
        printf("\n");                      // quebra de linha ao final de cada linha
    }

    return 0;
}
Digite matriz[0][0]: 1
Digite matriz[0][1]: 2
Digite matriz[1][0]: 3
Digite matriz[1][1]: 4

Matriz:
   1   2
   3   4

4. Operações Clássicas com Matrizes

4.1 — Troca de linhas

Para trocar duas linhas de uma matriz, usamos variáveis temporárias — o mesmo padrão do swap de variáveis, mas dentro de um loop de colunas:

#include <stdio.h>

int main() {
    int m[2][2], temp, i;

    // Leitura da matriz
    printf("Digite [0][0]: "); scanf("%d", &m[0][0]);
    printf("Digite [0][1]: "); scanf("%d", &m[0][1]);
    printf("Digite [1][0]: "); scanf("%d", &m[1][0]);
    printf("Digite [1][1]: "); scanf("%d", &m[1][1]);

    // Troca das linhas 0 e 1
    for (i = 0; i < 2; i++) {
        temp   = m[0][i];    // guarda elemento da linha 0
        m[0][i] = m[1][i];   // sobrescreve com linha 1
        m[1][i] = temp;      // restaura na linha 1
    }

    // Impressão
    printf("\nMatriz após troca:\n");
    printf("%d %d\n", m[0][0], m[0][1]);
    printf("%d %d\n", m[1][0], m[1][1]);
    return 0;
}
AntesDepois
1 2 / 3 43 4 / 1 2

4.2 — Soma de matrizes

#include <stdio.h>
#define L 2
#define C 3

int main() {
    int a[L][C] = {{1,2,3},{4,5,6}};
    int b[L][C] = {{7,8,9},{1,2,3}};
    int soma[L][C];
    int i, j;

    for (i = 0; i < L; i++)
        for (j = 0; j < C; j++)
            soma[i][j] = a[i][j] + b[i][j];

    printf("Resultado da soma:\n");
    for (i = 0; i < L; i++) {
        for (j = 0; j < C; j++)
            printf("%4d", soma[i][j]);
        printf("\n");
    }
    return 0;
}
Resultado da soma:
   8  10  12
   5   7   9

4.3 — Transposta de uma matriz

A transposta troca linhas por colunas: o elemento [i][j] vai para [j][i].

#include <stdio.h>
#define N 3

int main() {
    int m[N][N] = {{1,2,3},{4,5,6},{7,8,9}};
    int t[N][N];   // matriz transposta
    int i, j;

    for (i = 0; i < N; i++)
        for (j = 0; j < N; j++)
            t[j][i] = m[i][j];   // troca índices

    printf("Transposta:\n");
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3d", t[i][j]);
        printf("\n");
    }
    return 0;
}
Transposta:
 1 4 7
 2 5 8
 3 6 9

5. Passando Matrizes para Funções

Matrizes, assim como arrays 1D, são passadas automaticamente por ponteiro — a função recebe o endereço do primeiro elemento e pode modificar os dados originais.

⚠️ Diferença crucial para funções: Ao declarar um parâmetro de função com array 2D, você pode omitir o número de linhas, mas o número de colunas é obrigatório — o compilador precisa dele para calcular o offset de cada linha.
#include <stdio.h>
#define COLS 3

// ✅ Correto: número de colunas especificado
void imprimirMatriz(int m[][COLS], int linhas) {
    int i, j;
    for (i = 0; i < linhas; i++) {
        for (j = 0; j < COLS; j++)
            printf("%4d", m[i][j]);
        printf("\n");
    }
}

// Equivalente com ponteiro explícito (C99+)
void dobrarElementos(int m[][COLS], int linhas) {
    int i, j;
    for (i = 0; i < linhas; i++)
        for (j = 0; j < COLS; j++)
            m[i][j] *= 2;   // modifica o original (passagem por ponteiro)
}

int main() {
    int tabela[2][COLS] = {{1,2,3},{4,5,6}};
    printf("Original:\n");
    imprimirMatriz(tabela, 2);

    dobrarElementos(tabela, 2);
    printf("Após dobrar:\n");
    imprimirMatriz(tabela, 2);
    return 0;
}
Original:
   1   2   3
   4   5   6
Após dobrar:
   2   4   6
   8  10  12
Por que a função modifica o original? Pela mesma razão dos arrays 1D: em C, arrays decaem para ponteiro quando passados para funções. A função não recebe uma cópia — recebe o endereço do primeiro elemento. Use const int m[][COLS] se quiser garantir que a função não modifique os dados.

6. C vs. Java — Matrizes

Aspecto C Java
Declaração int m[3][4]; int[][] m = new int[3][4];
Armazenamento Bloco contíguo (row-major) Array de arrays (referências)
Linhas de tamanhos diferentes (jagged) ❌ Não suportado nativamente ✅ Cada linha pode ter tamanho diferente
Verificação de limites ❌ Nenhuma — comportamento indefinido ✅ Lança ArrayIndexOutOfBoundsException
Tamanho em tempo de execução sizeof(m) / sizeof(m[0]) (apenas local) m.length e m[0].length
Passagem para função Por ponteiro (obriga informar colunas) Por referência automática

Side-by-side: soma de matriz 2×2

C
int a[2][2] = {{1,2},{3,4}};
int b[2][2] = {{5,6},{7,8}};
int s[2][2];
for (int i=0; i<2; i++)
  for (int j=0; j<2; j++)
    s[i][j] = a[i][j]+b[i][j];
Java
int[][] a = {{1,2},{3,4}};
int[][] b = {{5,6},{7,8}};
int[][] s = new int[2][2];
for (int i=0; i<2; i++)
  for (int j=0; j<2; j++)
    s[i][j] = a[i][j]+b[i][j];

Quiz — Aula 25

1. Qual é a saída do trecho abaixo?

int m[2][3] = {{1,2,3},{4,5,6}};
printf("%d", m[1][2]);

2. Qual declaração de parâmetro está incorreta para uma função que recebe a matriz int m[3][4]?

3. Após a inicialização parcial int m[3][3] = {{1},{2,3}};, qual é o valor de m[2][0]?

4. O que a linha t[j][i] = m[i][j]; dentro de loops aninhados calcula?

5. Em C, ao passar int m[3][4] para uma função, o que a função recebe?

6. Qual é o tamanho em bytes de int m[4][5] numa máquina onde sizeof(int) == 4?

7. Em Java, é possível criar um array 2D onde cada linha tem um tamanho diferente. Em C isso:

8. Qual é a saída do código abaixo?

int m[2][2] = {1, 2, 3, 4};
printf("%d %d", m[0][1], m[1][0]);