Ponteiros e matrizes
Embora pensemos em matrizes como uma estrutura multidimensional, contendo linhas e colunas, as matrizes são armazenadas na memória de forma linear, como um vetor de vetores.
Para facilitar, vamos relembrar a declaração de uma matriz em C:
int matriz[2][2]; // matriz[linhas][colunas]
Se atribuírmos valores à matriz, observaremos que cada linha da matriz é um vetor.
int matriz[2][2] = {
{25,50}, // isso é um vetor
{7, 14} // isso é outro vetor
};
Sim, eu sei que isso pode ser um pouco confuso, mas vou tentar explicar detalhadamente a seguir.
🤯 Expandindo a mente
Recapitulando:
- 1️⃣ No conteúdo sobre Ponteiros e Vetores, vimos que a navegação em um vetor pode acontecer da forma simples: somando um valor inteiro ao endereço de memória da primeira posição, certo?
- 2️⃣ No conteúdo sobre Aritmética de Ponteiros, vimos que as operações de adição e subtração a endereços de memória não levam em consideração o número absoluto, mas sim o espaço de memória utilizado por cada tipo de dado (4 bytes para um inteiro, por exemplo).
Como vetores e matrizes são estruturas de dados homogêneas (ou seja: armazenam dados do mesmo tipo), é fácil mudar de uma posição para outra pois o avanço na memória terá sempre a mesma quantidade: aquela necessária para armazenar o tipo de dado.
Se você entendeu até aqui, continue :)
🤔 Vetor de vetor
No exemplo de código anterior, como a matriz seria capaz de diferenciar um vetor do outro? A solução é bem interessante: quando declaramos uma matriz, já informamos a quantidade de linhas (número de itens do vetor de vetores), bem como o número de colunas (número de itens de cada vetor). Também temos o tipo de dado utilizado.
No código acima, matriz
é um vetor de DUAS posições. Cada posição de matriz
consiste em um vetor de números inteiros, com duas posições, totalizando 8 bytes de armazenamento.
Vejamos:
#include <stdio.h>
int main()
{
int matriz[2][2] = {
{25,50}, // isso é um vetor
{7, 14} // isso é outro vetor
};
printf("Matriz: %p\n", matriz);
printf("Matriz: %p\n", matriz+1);
return 0;
}
Saída:
Matriz: 0x7ffe85a185f0
Matriz: 0x7ffe85a185f8
Resumidamente:
*(matriz+linha)
🚪 Acessando as colunas
Agora que já sabemos navegar entre as linhas da matriz, precisamos voltar nossas atenções para a navegação entre os elementos da lista. Felizmente, aqui não há muito segredo: estamos lidando com um vetor de inteiros.
Precisamos, a partir de uma posição inicial (a que representa a linha da matriz), selecionar incrementar um valor que representa o índice da coluna:
*(*(matriz+linha)+coluna)
A sintaxe é um pouco estranha, então vamos entender por partes:
- Com
*(matriz+linha)
, acessamos o vetor que contém a linha desejada; - Com
*(...+coluna)
, especificamos qual a coluna desejada.
👨💻 Vamos ao código
Como já estamos acostumados, podemos acessar as posições da matriz usando a tradicional notação matriz[linha][coluna]
:
#include <stdio.h>
int main()
{
int matriz[2][2] = {{1,2}, {3,4}};
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
printf("matriz[%d][%d] => %d\n", i,j,matriz[i][j]);
}
}
return 0;
}
Alternativamente, podemos fazer uso de ponteiros: *(*(matriz+linha)+coluna)
:
#include <stdio.h>
int main()
{
int matriz[2][2] = {{25,50}, {7,14}};
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
printf("matriz[%d][%d] => %d\n", i,j, *(*(matriz+i)+j));
}
}
return 0;
}
📖 Bibliografia
Livros
- Backes, A. (2018). Linguagem C - Completa e Descomplicada.