Introdução às matrizes
[
Memória |
Parâmetros |
Vetores |
C
]
Nesta seção examinaremos resumidamente como utilizar matrizes com a linguagem C.
Da mesma forma que o conceito de vetor é útil quando necessita-se de uma grande quantidade de valores
associados, todos eles, a um mesmo tipo de dado (como as várias notas de determinado aluno),
o conceito de matriz é útil quando naturalmente os dados considerados apresentam
duas dimensões.
Um exemplo é quando precisamos processar dados de um grupo de indivíduos (e.g. alunos), cada um deles com várias
medidas (e.g. notas - vide figura 1).
Também vale a pena destacar que, em várias linguagens de programação (como C e Python), a implementação de matriz é
feita por meio de vetor de vetores.
Desse modelo, em ambas pode-se tratar cada linha como um vetor.
Por exemplo, se a matriz recebe o nome de M, então M[0] é sua primeira linha,
M[1] a segunda linha e assim por diante.
Se for necessário pegar um elemento específico da matriz, deve-se usar dois colchetes, como em
M[i][j], que devolve o valor da linha i na coluna j
(e.g. M[0][0] devolve o valor da primeira posição da matriz e M[1][0] devolve o valor do
primeiro elemento sua segunda linha).
1. Matrizes: sequência contígua de variáveis
Do ponto de vista computacional a implementação de matrizes segue o princípio dos vetores, uma matriz ocupa
uma porção contígua da memória do computador, servindo para representar o conceito matemático associado.
Lembrando que ao representar um vetor o acesso ao elemento da posição i pode ser feito por meio da sintaxe
vet[i], no caso de matriz é necessário indicar em qual linha i e em qual coluna j o elemento está,
por exemplo, se a variável tem por nome Mat, usaria Mat[i][j].
Este tipo de estrutura de dados é natural quando os dados apresentam 2 atributos. Por exemplo, em uma sala de aula,
o professor precisa manter informações dos resultados obtidos pelos alunos em várias atividades, assim pode-se utilizar uma
matriz para representar estes dados: as atividades de cada aluno estão em uma única linha da matriz Mat
(e.g., Mat[i][0] é o resultado da atividade 0 para o aluno i).
Fig. 1. Ilustração de como uma matriz é representada na "memória" do computador.
Mas como é possível implementar computacionalmente esse tipo de estrutura?
Na figura acima está representado uma matriz conceitual, com a ideia de alunos e notas, e à direita como estes dados estão
na memória do computador, supondo-se M+1 alunos e N+1 atividades.
Se na representação computacional, o nome da matriz for Mat, então os dados correspondentes ao
aluno 0 são: Mat[0][1], Mat[0][1] e assim por diante até o Mat[0][N].
1.1. Matrizes: como parâmetro de função
Do mesmo modo que vetores, ao passar uma matriz como parâmetro de uma função, este funcionará como parâmetro por referência
(ou por endereço). Ou seja, é passada uma referência ao parâmetro efetivo (em que chamou a função)
de modo que qualquer alteração dentro da função, no parâmetro formal, significará que o valor na matriz
que foi passada como parâmetro (no local que chamou a função e portanto o parâmetro efetivo) será alterado.
Na linguagem C as matrizes (e vetores) são passados por referência. O exemplo abaixo ilustra
que alterar os dados de uma matriz dentro de uma função implica em alterar a matriz que lhe foi passada (parâmetro efetivo).
Tab. 1. Matrizes passadas via parâmetro para funções (equivale à uma referência à uma matriz "externa").
Função com computa soma de 2 matrizes em C |
Exemplo em C |
#include <stdio.h>
#define NL 20 // constante para maximo de linhas
#define NC 20 // constante para maximo de colunas
// Funcao para gerar nova matriz MA + MB
void somaMat (int MA[][NC], int MB[][NC], int MC[][NC], int nL, int nC) {
int i, j; // auxiliar, para indexar os matrizes
for (i=0; i< nL; i++) // "Ler" nL x nC valores
for (j=0; j< nC; j++) // inteiros armazenando-os
MC[i][j] = MA[i][j] + MB[i][j];
}
// Funcao para entrar matriz nL x nC, linha por linha
void lerMatriz (int mat[][NC], int nL, int nC) {
int i,j; // declara indices
for (i=0; i<nL; i++) // i entre 0 e nL-1
for (j=0; j<nC; j++) // j entre 0 e nC-1
scanf("%d", &mat[i][j]);
}
// Funcao para imprimir matriz nL x nC, linha por linha
void imprimeMatriz (int mat[][NC], int nL, int nC) {
int i,j; // declara indices
for (i=0; i< nL; i++) { // i entre 0 e nL-1
printf("%2d: ", i); // "Imprime" numero desta linha
for (j=0; j< nC; j++) // j entre 0 e nC-1
printf("%3d ", mat[i][j]); // em 3 espacos
printf("\n"); // Mude de linha
}
}
int main (void) {
int i, j; // auxiliar, para indexar os matrizes
int m, n; // tamanho util das matrizes
int matA[NL][NC], matB[NL][NC], matC[NL][NC]; // Matriz para inteiros (ate' NL*NC elementos)
scanf("%d %d", &m, &n);
printf("Entra matriz A:\n"); lerMatriz(matA, m, n);
printf("Entra matriz B:\n"); lerMatriz(matB, m, n);
printf("Gera matriz C:\n"); somaMat(matA, matB, matC, m, n); // parametros efetivos
printf("Matriz A:\n"); imprimeMatriz(matA, m, n); // 'matA' e' parametro efetivo
printf("Matriz B:\n"); imprimeMatriz(matB, m, n); // aqui e' 'matB'
printf("Matriz C:\n"); imprimeMatriz(matC, m, n); // aqui e' 'matC'
return 0;
} |
|
1.2. Matrizes: uma linha equivale a um vetor
Uma vez que os elementos em uma linha da matriz estão em posições contíguas da memória, eles podem ser
olhados como um vetor, novamente o contexto determina o significado dos dados.
Assim, se tivermos uma função soma_vetor que recebe como parâmetro um vetor (e sua dimensão) e que gera a soma de seus elementos,
pode-se fazer a seguinte chamada: soma_vetor(mat[i],n), para qualquer i entre 0 e M do exemplo acima.
Desse modo, o exemplo abaixo ilustra uma função preparada para somar elementos de um vetor (soma += vet[i];) sendo usada para
somar as linhas de uma matriz.
Então, na execução do laço dentro função, o comando usando o parâmetro formal soma, soma += vet[i] equivalerá
ao código soma += mat[k][i]; no trecho que invocou a função soma_vetor.
Tab. 2. Uma linha de um matriz é na verdade um vetor.
Função de função para somar elementos de vetor sendo usado com linhas de matrizes em C |
Exemplo em C |
#include <stdio.h>
...
int soma_vetor (int vet[], int n) {
int i, soma = 0;
for (i=0; i < n; i++)
soma += vet[i];
return soma;
}
int main (void) {
int mat[NL][NC]; ...
...
print("soma linha %d : %d\n", i, soma_vetor(mat[i], n));
...
return 0;
} |
|
2. Matrizes em C
Como em C deve-se sempre declarar o tipo da variável, no caso de matriz deve-se declarar seu tipo e seu tamanho.
No exemplo abaixo ilustramos as declarações e uso de matrizes dos tipos básicos int, char e float.
Tab. 3. Exemplos de tratamento de matrizes em C (com inteiros, caracteres e "flutuantes").
Matrizes em C |
Matriz de inteiros |
Matriz de caracteres |
Matriz de flutuantes |
#include <stdio.h>
#define NL 20 // constante para maximo de linhas
#define NC 20 // constante para maximo de colunas
int main (void) {
int i, j; // auxiliar, para indexar os matrizes
int nL, nC; // tamanho util das matrizes
int mat[NL][NC]; // Matriz para inteiros (ate' NL*NC elementos)
scanf("%d %d", &nL, &nC);
for (i=0; i< nL; i++) // "Ler" nL x nC valores
for (j=0; j< nC; j++) // inteiros armazenando-os
scanf("%d", &mat[i][j]); // na matriz
for (i=0; i< nL; i++) { // "Imprimir" os nL x nC
printf("%2d: ", i); // "Imprime" numero desta linha
for (j=0; j< nL; j++) // valores inteiros, ajustando
printf("%3d ", mat[i][j]); // em 3 espacos
printf("\n"); // Mude de linha
}
return 0;
} |
|
#include <stdio.h>
#define NL 20 // constante para maximo de linhas
#define NC 20 // constante para maximo de colunas
int main (void) {
int i, j; // auxiliar, para indexar os matrizes
int nL, nC; // tamanho util dos matrizes
char matC[NL][NC]; // Matriz para caracteres
scanf("%d %d", &nL, &nC);
for (i=0; i< nL; i++) // "Ler" nL x nC valores
for (j=0; j< nC; j++) // tipo "char" armazenando-os
scanf("%c", &matC[i][j]); // na matriz
for (i=0; i< nL; i++) { // "Imprimir" os nL x nC
printf("%2d: ", i); // "Imprime" numero desta linha
for (j=0; j< nC; j++) // valores tipo "char",
printf("%2c", matC[i][j]); // ajustando em 2 espacos
printf("\n"); // Mude de linha
}
return 0;
} |
#include <stdio.h>
#define M 20 // usado para constante
int main (void) {
int i, j; // auxiliar, para indexar os matrizes
int nL, nC; // tamanho util dos matrizes
float matF[NL][NC]; // Matriz para caracteres
scanf("%d %d", &nL, &nC);
for (i=0; i< nL; i++) // "Ler" nL x nC valores
for (j=0; j< nC; j++) // tipo "char" armazenando-os
scanf("%f", &matF[i][j]); // na matriz
for (i=0; i< nL; i++) { // "Imprimir" os nL x nC
printf("%2d: ", i); // "Imprime" numero desta linha
for (j=0; j< nC; j++) // valores tipo "float",
printf("%5.1f", matF[i][j]); // usando 5 esp. e 1 dec.
printf("\n"); // Mude de linha
}
return 0;
} |
No C padrão NÃO é possível declarar as dimensões da matriz usando a variável que será usada para
informar o número efetivo de posições "úteis" na matriz, ou seja, não tente fazer algo como:
int m, n; float mat[m][n];, pode ser que em seu equipamente a versão C
utilizada aceite esse construção dinâmica, mas em várias outras não funcionará, logo evite.
A razão disso é que C, por ser uma linguagem compilada, durante a fase de compilação deve-se reservar o
espaço máximo a ser usado pelo matriz.
Já as variáveis m e n só serão conhecidas durante a execução do programa.
Apesar de algumas implementações de compiladores C permitirem esse tipo de declaração "dinâmica",
NÃO usem sob pena de seu programa não funcionar em outros compiladores.
Vejamos o exemplo da função soma_vetor sendo chamada com cada linha de uma matriz, com código completo em C.
// Exemplo de matriz em Python passando linha em funcao que trabalha com vetor
#include <stdio.h>
#define MAXL 20 // usar no maximo 20 linhas
#define MAXC 20 // usar no maximo 20 colunas
int soma_vet (int vet[], int n) {
int soma = 0, i;
for (i=0; i<n; i++)
soma += vet[i];
return soma;
}
int main (void) {
int mat[MAXL][MAXC]; // declara que existira uma matriz (vetor de vetor)
int i, j, m = 3, n = 4; // dimensoes fixas por simplicidade
for (i=0; i<m; i++) {
for (j=0; j<n; j++) {
mat[i][j] = i*n + j; // como ja' existe espaco reservado atribua "i*m + j" para a posicao linha i e coluna j
printf(" %3d", mat[i][j]); // imprime sem mudar de linha
}
printf("\n"); // muda de linha
}
printf("Imprime somas das linhas\n");
for (i=0; i<m; i++)
printf("Linha %d tem soma: %3d\n", i, soma_vet(mat[i], n)); // %3d ajusta 3 casas 'a direita
return 1;
}
Bem, em resumo é isso.
Leônidas de Oliveira Brandão
http://line.ime.usp.br
Alterações
:
2021/06/22: pequenos acertos (ä-â, ë-ê, é...), numeração de seções, alterações visibilidade desse rodapé
2020/08/15: novo formato, pequenas revisões
2020/05/18: inserido um código Python explicando como criar matrizes.
2019/06/06: vários pequenos acertos ao longo do texto.