Uma matriz em C parece ser um vetor de vetores, mas é algo um pouco mais complexo. Existem dois jeitos de se lidar com matrizes em C. O primeiro só funciona com matrizes de tamanho fixo mas é mais fácil de entender e implementar, enquanto o segundo funciona com matrizes arbitrárias mas é mais complexo.
O jeito mais simples de declarar matrizes em C é lembrar que o conceito de matriz é um vetor de vetores, e C te deixa expressar isso naturalmente. Para declarar uma matriz assim, faça
<tipo> <nome>[n][m];Isso pode ser extendido para valores arbitrários de n e m.
Matrizes assim em C são que nem vetores, mas mais complicadas. Por exemplo, o seguintes códigos funcionam:
#include <stdio.h> void imprime_mat(int x[3][3], int n) { int i ,j; for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { printf("%d ", x[i][j]); } printf("\n"); } } int main(int argc, char *argv[]) { int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; imprime_mat(mat, 3); return 0; }e
#include <stdio.h> void imprime_mat(int x[][3], int n) { int i ,j; for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { printf("%d ", x[i][j]); } printf("\n"); } } int main(int argc, char *argv[]) { int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; imprime_mat(mat, 3); return 0; }mas os seguintes dão erro de compilação:
#include <stdio.h> void imprime_mat(int x[][], int n) { int i ,j; for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { printf("%d ", x[i][j]); } printf("\n"); } } int main(int argc, char *argv[]) { int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; imprime_mat(mat, 3); return 0; }
e
#include <stdio.h> void imprime_mat(int *x[], int n) { int i ,j; for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { printf("%d ", x[i][j]); } printf("\n"); } } int main(int argc, char *argv[]) { int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; imprime_mat(mat, 3); return 0; }
Efetivamente, uma função que usa matrizes em C dessa forma vai necessariamente precisar conhecer em tempo de compilação o tamanho da matriz. Caso isso não aconteça, o compilador não consegue gerar código para acessá-la. Isso é por causa do layout de memória que C usa. escrever o nome da matriz em C é um ponteiro para o primeiro elemento dela, mas esse ponteiro não existe na memória, então não é possível passar um ponteiro.
Então o jeito mais simples de lidar com matrizes é declarar um vetor de vetores, mas isso tem seus problemas.
O segundo jeito é declarar um vetor para guardar todos os elementos da matriz e fazer você mesmo as contas para acessá-los. Uma matriz de dimensão n x m tem n*m elementos. Se você escolher colocar as linhas da matriz uma depois da outra na memória, você pode então saber que o elemento (i,j) da matriz vai ficar na posição m*i + j. Por isso era necessário especificar, ao passar a matriz pra função, quantas colunas ela tinha.
Se vc faz essa conta, o código para acessar o elemento i,j da matriz então fica
mat[m*i + j]
Assim podemos fazer um código para somar duas matrizes da seguinte forma (guardando o resultado numa terceira):
void soma_mat(int *a, int *b, int *c, int linhas, int colunas) { int i,j, tmp; for (i = 0; i < linhas; ++i) { for (j = 0; j < colunas; ++j) { tmp = colunas*i+j; c[tmp] = a[tmp] + b[tmp]; } } }
Ou fazer o código para multiplicar uma matriz por um vetor
double mult_mat_vec(double *mat, int linhas, int colunas, double *vec, double *res) { int i, j; double s = 0; for (i = 0; i < linhas; ++i) { s = 0; for (j = 0; j < colunas; ++j) { s += mat[colunas*i+j]*vec[j]; } res[i] = s; } }
Se você quiser mesmo acessar os elementos de uma matriz como
mat[i][j]tem um jeito para resolver isso. Basta notar que para a função você vai passar um ponteiro para um ponteiro (já que os colchetes aparecem duas vezes). Então você quer dois vetores: um para os elementos da matriz e um para os ponteiros para o primeiro elemento de cada linha. Ou seja:
int mat[n][m]; int *p[n], i; for (i = 0; i < n; ++i) p[i] = &mat[i][0];com isso você pode declarar uma função para receber uma matriz como
int func(int **mat, int linhas, int colunas) {só que você tem que passar p para a função, e não m, já que é p que tem os ponteiros. Podemos ver que isso funciona fazendo a dereferência dos ponteiros manualmente.
Vamos assumir que temos um sistema linear com n equações e n variáveis. Podemos representar esse sistema como uma matrix n por n+1 (já que temos que considerar os termos constantes do Ax = b). Um jeito simples de resolver esse sistema (e numericamente instável, mas fácil de implementar) é a eliminação gaussiana. Ela consiste de, para cada linha da matriz,
Para isso vamos usar uma função que usa ponteiros e vetores:
void soma_const(double *a, double *b, int n, double c, double d, double *res) { int i; for (i = 0; i < n; ++i) res[i] = c*a[i]+d*b[i]; }
O algoritmo de eliminação gaussiana então é (assumindo que não temos zeros na matriz):
void inverte_m(double *mat, int n) { int i, j, m = n+1; for (i = 0; i < n; ++i) { soma_const(mat+m*i, mat+m*i, m, 1./mat[m*i+i], 0, mat+m*i); // a = a/a[i] + 0*a for (j = 0; j < n; ++j) { if (i == j) continue; soma_const(mat+m*i, mat+m*j, m, -mat[j*m+i], 1, mat+m*j); // b = b - a*b[i] } } for (i = 0; i < n; ++i) printf("X%d = %lf\n", i, mat[m*i+n]); }
E assim podemos resolver um sistema linear de n variáveis, assumindo que não temos nenhum problema de super ou sub determinação.
Traduzir o código de invertem para funcionar com matrizes de tamanho fixo como é o tipo 1 dessa aula.
Escrever uma função para transpor uma matriz.
Date: 2010-09-25 17:21:20 BRT
HTML generated by org-mode 6.21b in emacs 23