Matrizes


Resumo:

Matrizes são estruturas bi-dimensionais utilizadas para armazenar dados de um mesmo tipo. Para declarar uma matriz use a seguinte construção:
tipo_da_matriz nome_da_matriz [num_linhas][num_colunas];

Para acessar os elementos da matriz, basta definir cada coordenada desejada entre colchetes, ou seja, use A[i][j] para acessar o elemento (i,j) da matriz A.

Uma matriz pode ser considerada como um vetor de vetores, assim, o nome da matriz, por exemplo A, é utilizado para referenciar toda a estrutura bidimensional de A, mas cada linha da matriz pode ser utilizada para referenciar uma coluna (correspondente aos elementos da linha A[i]). Quando os dois índices são fornecidos, então acessamos um elemento da matriz. Veja que dessa forma, não é possível referenciar uma coluna diretamente.

Descrição:

Uma matriz é uma estrutura bidimensional capaz de armazenar dados de um mesmo tipo. Podemos considerar o conceito de matriz como uma extensão do conceito de vetores, onde vetores corresponderia a uma estrutura unidimensional. As matrizes (e vetores) só podem ser acessados através de índices inteiros, ou seja, a dimensão de uma matriz é definida através de 2 números, o número de linhas e o de colunas. Na linguagem C, o primeiro índice (escrito mais perto do nome da matriz) sempre corresponde à linha, e o segundo índice, à coluna a ser acessada.

Como declarar uma matriz

Uma matriz deve ser declarada da seguinte forma:

tipo_da_matriz nome_da_matriz [num_linhas][num_colunas];

Exemplos:

    int   matInt [6][2]; /* matriz com 6 linhas e 2 colunas de inteiros */
float matReal [5][7]; /* matriz com 5 linhas e 7 colunas de floats */
char matChar [3][4]; /* matriz com 3 linhas e 4 colunas de chars */

Observe que a declaração de matrizes é semelhante à declaração de vetores, porém é necessário definir o tamanho da segunda dimensão. Na primeira declaração, todos os elementos da matriz matInt são inteiros. O primeiro número define o número de linhas e o segundo o número de colunas a serem reservados na memória do computador para armazenar essa matriz. A segunda declaração reserva uma matriz de floats, com 5 linhas e 7 colunas.

Uma vez declarada, por exemplo a matriz matChar com 3 linhas e 4 colunas, é reservada uma região na memória suficiente para armazenar toda a matriz. A figura abaixo mostra essa estrutura:

Linha
Coluna
Conteúdo
Comentário
0
0
? valor inicial desconhecido
0
1
? valor inicial desconhecido
0
2
? valor inicial desconhecido
0
3
? valor inicial desconhecido
1
0
? valor inicial desconhecido
1
1
? valor inicial desconhecido
1
2
? valor inicial desconhecido
1
3
? valor inicial desconhecido
2
0
? valor inicial desconhecido
2
1
? valor inicial desconhecido
2
2
? valor inicial desconhecido
2
3
? valor inicial desconhecido

Figura 1: área da memória reservada para a matriz matChar. Observe que são reservadas 12 posições, cada uma das 3 linhas tem 4 colunas.

Observe que a matriz pode ser considerada como um vetor de vetores, ou seja, a matriz é um vetor de linhas, e cada linha é um vetor de colunas. Essa idéia será explorada nos exemplos a seguir.

Como usar matrizes em seus programas

Assim como vetores, cada posição da matriz funciona como uma variável, que pode ser acessada através do nome da matriz e os índices entre colchetes que indicam a coordenada desejada. Por exemplo, o trecho de programa abaixo coloca o caractere '*' em cada uma das posições do vetor matChar:

for (lin = 0; lin < 3; lin++) 
for (col = 0; col < 4; col++)
/* lembre-se que um char deve vir entre apostrofes */
matChar[lin][col] = '*';

O índice na verdade pode ser uma expressão, mas assim como vetores, tenha sempre cuidado de fornecer um índice válido.

Exemplos comentados

PROBLEMA 1

Faça um programa que leia , e os elementos de uma matriz real quadrada e imprima quais linhas, colunas e diagonais (principal e secundária) da matriz são compostas apenas por zeros.

Solução (veja os comentários no próprio programa):

#include <stdio.h>
#define MAX 100
#define SIM 1
#define NAO 0
#define EPS 0.001

/*
função saoIguais: compara se 2 numeros reais são iguais
devido a precisão numérica, dois reais NÃO devem ser comparados
diretamente para determinar igualdade
*/
int saoIguais(float f1, float f2) {
int res = NAO;
float dif = f1 - f2;
if (dif < EPS && dif > -EPS)
res = SIM;
return res;
}

int main () {
float A [MAX][MAX]; /* reservando espaço para uma matriz MAX x MAX */
int m, lin, col, soZero;

/* leitura dos dados */
printf("Entre com o tamanho da matriz quadrada: ");
scanf("%d", &m);
printf("Entre com os elementos da matriz\n");
for (lin=0; lin<m; lin++)
for (col=0; col<m; col++)
scanf("%f", &A[lin][col]);

/* verifica se existe alguma linha só com zeros */
for (lin = 0; lin < m; lin++) { /* para cada linha ... */
soZero = SIM; /* soZero é um indicador de passagem que */
for (col = 0; col < m; col++) /* muda de valor se a linha conter algum */
if (saoIguais(A[lin][col], 0.0) NAO)
soZero = NAO; /* elemento diferente de zero */
if (soZero
SIM) /* imprime a resposta parcial */
printf("A linha %d tem so zeros\n", lin);
}

/* verifica se existe alguma coluna só com zeros */
for (col = 0; col < m; col++) {
soZero = SIM;
for (lin = 0; lin < m; lin++)
if (saoIguais(A[lin][col], 0.0) NAO)
soZero = NAO; /* elemento diferente de zero */
if (soZero
SIM)
printf("A coluna %d tem so zeros\n", col);
}

/* verifica diagonal principal */
soZero = SIM;
for (lin = 0; lin < m; lin++)
/* na diagonal, lin é igual a col */
if (saoIguais(A[lin][lin], 0.0) NAO)
soZero = NAO;
if (soZero
SIM)
printf("A diagonal principal tem so zeros\n");

/* verifica diagonal secundária */
soZero = SIM;
for (lin = 0; lin < m; lin++)
if (saoIguais(A[lin][m-1- lin], 0.0) NAO)
soZero = NAO;
if (soZero
SIM)
printf("A diagonal secundaria tem so zeros\n");

return 0;
}

PROBLEMA 2 - FUNÇÕES COM MATRIZES:

O uso de matrizes em funções é bem semelhante ao uso de vetores, ou seja, sempre por referência. Como exemplo, vamos escrever um programa que lê duas matrizes e calcula o seu produto, mas dessa vez, usando funções para ler e imprimir as matrizes.

Vamos primeiro escrever uma função que carrega uma matriz real .

void leMatriz(float M[MAX][MAX], int m, int n) {
int lin, col;
for (lin=0; lin<m; lin++)
for (col=0; col<n; col++)
scanf("%f", &M[lin][col]);
}

Observe a definição da matriz como parâmetro da função leMatriz e que na chamada da função scanf, o endereço de cada elemento é passado através de &M[lin][col]). A dimensão das linhas na verdade é facultativa, ou seja, o protótipo:

void leMatriz(float M![][MAX], int m, int n);
também é válido. Porém, a definição da segunda dimensão é obrigatória, pois caso contrário o compilador não seria capaz de calcular as posições corretas dos elementos da matriz na memória (não saberia quantas colunas pular para chegar na próxima linha). Acreditamos que essa notação possa ser confusa no início, e portanto manteremos a notação que define as duas dimensões.

Vamos agora escrever uma função para imprimir uma matriz real :

void imprimeMatriz(float M[MAX][MAX], int m, int n) {
int lin, col;
for (lin=0; lin<m; lin++) {
for (col=0; col<n; col++)
printf("%.2f \t", M[lin][col]);
printf("\n"); /* muda de linha */
}
}

Finalmente, vamos escrever o programa que multiplica duas matrizes:

#include <stdio.h>
#define MAX 100

void leMatriz(float M[MAX][MAX], int m, int n);
void imprimeMatriz(float M[MAX][MAX], int m, int n);

/* Seja A uma matriz de dimensão r x s e B uma matriz de
dimensão s x t. Esse programa calcula o produto de A x B,
resultando em uma matriz C de dimensão r x t
*/
int main () {
float A[MAX][MAX], B[MAX][MAX], C[MAX][MAX];
int r,s,t;
int lin, col, k;
float soma;

printf("Este programa calcula o produto de 2 matrizes\n");

printf("Digite as dimensões das matrizes: ");
scanf("%d %d %d", &r, &s, &t);

printf("Entre com os valores da matriz A\n");
leMatriz(A, r, s);
printf("Entre com os valores da matriz B\n");
leMatriz(B, s, t);

/* a matriz C tem r linhas e t colunas */
for (lin = 0; lin < r; lin++) {
for (col = 0; col < t; col++) {
/* calculo do produto da linha lin pela coluna col */
soma = 0;
for (k = 0; k<s; k++)
soma = soma + A[lin][k]*B[k][col];
C[lin][col] = soma;
}
}
/* vamos imprimir o resultado */
imprimeMatriz(C, r, t);
return 0;
}

Sabemos que um elemento da saída pode ser calculado através da fórmula:


Observe que há 3 comandos for encaixados. Dois deles são utilizados para visitar todos os elementos da saída (a matriz tem dimensão , e o terceiro é utilizado para calcular o valor da matriz em cada posição, variando .

Matrizes e Vetores

Uma matriz pode ser considerada como um vetor de vetores, assim, o nome da matriz (por exemplo A) é utilizado para referenciar toda a estrutura bidimensional de A (veja, em particular, como a matriz A foi passada para as funções leMatriz e imprimeMatriz dentro do programa anterior).

Mas com A é um vetor de vetores, cada linha da matriz pode ser utilizada para referenciar um vetor coluna (a linha A[i] é um apontador para o ínicio do vetor coluna correspondente à linha A[i]). Quando os dois índices são fornecidos, então acessamos um elemento da matriz. Veja que não é possível referenciar uma coluna diretamente como um vetor devido a maneira utilzada para armazenar uma matriz (veja a tabela 1), ou seja, a matriz mantém a ordem linear dos elementos em uma linha, mas não mantém essa ordem para os elementos de uma coluna.

Vamos ver um exemplo, usando o mesmo programa de produto de matrizes, e a função produtoEscalar visto na aula sobre funções com vetores. Para sua conveniência, a função produtoEscalar é copiada abaixo:

float produtoEscalar (float V1[MAX], float V2[MAX], int N) {
int i;
float res = 0;
for (i=0; i<N; i++)
res = res + V1[i] * V2[i];
return res;
}

Observe que o procedimento para multiplicar uma linha da matriz A por uma coluna da matriz B é o mesmo procedimento do produto escalar. Sabendo que cada linha da matriz pode ser considerado um vetor (mas não as colunas), o seguinte programa calcula o produto de duas matrizes:

#include <stdio.h>
#define MAX 100

void leMatriz(float M[MAX][MAX], int m, int n);
void imprimeMatriz(float M[MAX][MAX], int m, int n);
float produtoEscalar (float V1[MAX], float V2[MAX], int N);

/* Seja A uma matriz de dimensão r x s e B uma matriz de
dimensão s x t. Esse programa calcula o produto de A x B,
resultando em uma matriz C de dimensão r x t
*/
int main () {
float A[MAX][MAX], B[MAX][MAX], C[MAX][MAX], vet[MAX];
int r,s,t;
int lin, col, k;

printf("Este programa calcula o produto de 2 matrizes\n");
printf("atraves do usa da funcao produtoEscalar \n");

printf("Digite as dimensoes das matrizes: ");
scanf("%d %d %d", &r, &s, &t);

printf("Entre com os valores da matriz A\n");
leMatriz(A, r, s);
printf("Entre com os valores da matriz B\n");
leMatriz(B, s, t);

/* a matriz C tem r linhas e t colunas */
for (lin = 0; lin < r; lin++) {
for (col = 0; col < t; col++) {
/* calculo do produto escalar da linha lin pela coluna col */
/* a linha pode ser passada diretamente, pois é um vetor */
/* a coluna precisa ser carregada em um vetor auxiliar */
for (k = 0; k<s; k++) vet[k] = B[k][col];

/* repare agora como podemos chamar a funcao produtoEscalar */
C[lin][col] = produtoEscalar(A[lin], vet, s);
}
}
/* vamos imprimir o resultado */
imprimeMatriz(C, r, t);
return 0;
}

Exercícios Recomendados

  1. Dizemos que uma matriz é um quadrado latino de ordem se em cada linha e em cada coluna aparecem todos os inteiros (ou seja, cada linha e coluna é permutação dos inteiros ).

Eloiza Sonoda