As matrizes estáticas podem ser definidas e acessadas de forma bastante simples:
int matriz[100][100] ; for (i = 0; i < 100; i++) for (j = 0; j < 100; j++) matriz[i][j] = i+j ;
Por outro lado, matrizes dinâmicas não são tão simples de alocar e usar. Esta página mostra alguns métodos de como fazê-lo.
Nas figuras a seguir, cada faixa de blocos de uma mesma cor representa uma linha da matriz:
Neste método, os elementos da matriz são alocados em um único vetor, linearmente. Os elementos da matriz são acessados explicitamente através de aritmética de ponteiros.
#define LIN 4 #define COL 6 int *mat ; int i, j ; // aloca um vetor com todos os elementos da matriz mat = malloc (LIN * COL * sizeof (int)) ; // percorre a matriz for (i = 0; i < LIN; i++) for (j = 0; j < COL; j++) mat[(i*COL) + j] = 0 ; // calcula a posição de cada elemento // libera a memória da matriz free (mat) ;
Apesar do acesso às posições da matriz ser menos intuitivo, esta abordagem é muito rápida no acesso à memória, pois todos os elementos da matriz estarão alocados em posições contíguas de memória, devido à sua boa localidade de referências.
Neste método, a matriz é vista e alocada como um vetor de ponteiros para linhas, que são vetores de elementos. O vetor de ponteiros de linhas e os vetores de cada linha são alocados separadamente.
A vantagem desta técnica é que o acesso aos elementos da matriz usa a mesma sintaxe do acesso a uma matriz estática, o que torna a programação mais simples. Entretanto, sua localidade de referências é pior que na abordagem anterior.
#define LIN 4 #define COL 6 int **mat ; int i, j ; // aloca um vetor de LIN ponteiros para linhas mat = malloc (LIN * sizeof (int*)) ; // aloca cada uma das linhas (vetores de COL inteiros) for (i = 0; i < LIN; i++) mat[i] = malloc (COL * sizeof (int)) ; // percorre a matriz for (i = 0; i < LIN; i++) for (j = 0; j < COL; j++) mat[i][j] = 0 ; // acesso com sintaxe mais simples // libera a memória da matriz for (i = 0; i < LIN; i++) free (mat[i]) ; free (mat) ;
Neste método, a matriz é vista e alocada como um vetor de ponteiros para linhas, mas as linhas são alocadas como um único vetor de elementos. O vetor de ponteiros de linhas e o vetor de elementos são alocados separadamente.
Além de usar a mesma sintaxe de acesso que uma matriz estática, esta abordagem tem mais duas vantagens: precisa somente de duas operações de alocação de memória e todos os elementos da matriz estão alocados sequencialmente na memória, o que facilita operações de cópia de matrizes (usando memcpy
) ou de leitura/escrita da matriz para um arquivo (usando fread
ou fwrite
).
#define LIN 4 #define COL 6 int **mat ; int i, j ; // aloca um vetor de LIN ponteiros para linhas mat = malloc (LIN * sizeof (int*)) ; // aloca um vetor com todos os elementos da matriz mat[0] = malloc (LIN * COL * sizeof (int)) ; // ajusta os demais ponteiros de linhas (i > 0) for (i = 1; i < LIN; i++) mat[i] = mat[0] + i * COL ; // percorre a matriz for (i = 0; i < LIN; i++) for (j = 0; j < COL; j++) mat[i][j] = 0 ; // libera a memória da matriz free (mat[0]) ; free (mat) ;
O método anterior pode ser modificado, juntando os ponteiros e as linhas da matriz em uma única área de memória:
#define LIN 4 #define COL 6 int **mat ; int i, j ; // aloca um vetor com os ponteiros e os elementos da matriz mat = malloc (LIN * sizeof (int*) + LIN * COL * sizeof (int)) ; // ajusta o ponteiro da primeira linha mat[0] = (int*) (mat + LIN) ; // ajusta os ponteiros das demais linhas (i > 0) for (i = 1; i < LIN; i++) mat[i] = mat[0] + (i * COL) ; // percorre a matriz for (i = 0; i < LIN; i++) for (j = 0; j < COL; j++) mat[i][j] = i ; // libera a memória da matriz free (mat) ;
Apesar de ser elegante, esta solução pode apresentar um desempenho fraco, devido a problemas de alinhamento da matriz no cache da memória RAM.
Caso seu código use matrizes dinâmicas com frequência, recomenda-se criar uma função genérica de alocação, encapsulando um dos métodos acima, como mostra este exemplo:
// funções de alocação de matriz genérica 2D void** aloca_matriz (int nlin, int ncol, int tamanho) ; void libera_matriz (void **mat) ; // aloca e libera uma matriz de floats float** mf ; mf = (float**) aloca_matriz (1000, 1000, sizeof (float)) ; ... libera_matriz (mf) ;
char**
, em seguida, o programa deve trocar a ordem das palavras a fim de ordená-las por ordem alfabética.Matriz[1][2][3] = 1 + 2 + 3 = 6