Módulo 6 – Matrizes
na Linguagem C
6.1 – Compreendendo as Matrizes
Muitas vezes em programas, é necessário que uma variável contenha muitos valores. Por exemplo, a variável nota pode controlar as notas obtidas por 100 alunos em um exame. Da mesma maneira, a variável salários poderia controlar os salários de cada funcionário em uma companhia. Uma matriz é uma estrutura de dados que pode armazenar múltiplos valores do mesmo tipo. Por exemplo, pode-se criar uma matriz que possa conter 100 valores do tipo int e uma Segunda matriz com 25 valores do tipo float.
Todo valor que você atribui a uma matriz precisa ser do mesmo tipo que o tipo da matriz. Neste módulo será mostrado como criar e trabalhar com matrizes em programas. Com o tempo, após o uso de matrizes, ficará claro como é simples o uso de matrizes.
6.2 – Declarando uma Matriz
Para declarar uma matriz, precisa-se especificar o tipo desejado (tal como int, float ou double), bem como o tamanho da matriz. Para especificar o tamanho de uma matriz, coloca-se o número de valores que a matriz pode armazenar dentro de colchetes após o nome da matriz. Por exemplo, a declaração à seguir cria uma matriz chamada notas, que pode armazenar 100 notas de exame do tipo int:
|
int notas
[100]; |
De
forma similar, a seguinte declaração cria uma matriz do tipo float, que contém
50 salários:
|
float salarios [50]; |
Quando
uma matriz é declarada, a Linguagem C aloca memória suficiente para conter
todos os elementos. O primeiro item está na posição 0. Por exemplo, nas
matrizes notas e salarios, os comandos a seguir
atribuem os valores 80 e 35000 aos primeiros elementos da matriz:
|
notas[0] = 80; salarios[0] = 35000; |
Como
o primeiro elemento da matriz inicia no deslocamento 0, o último elemento da
matriz ocorre uma posição antes do tamanho da matriz. Dadas as matrizes
anteriores, os comandos a seguir atribuem valores ao último elemento de cada
matriz:
|
notas[99] = 65; salarios[49] = 250000; |
6.3 – Compreendendo os Requisitos de Armazenamento
de uma Matriz
Ao
declarar uma matriz, o compilador aloca memória suficiente para conter o número
de valores especificado. A quantidade real de memória que o compilador aloca
depende do tipo da matriz. Por exemplo, uma matriz de 100 elementos do tipo int
normalmente irá requerer 100*2 ou 200 bytes de memória. Por outro lado, uma
matriz de 100 elementos do tipo float irá requerer 100*4 bytes ou 400 bytes. O
programa abaixo, usa o operador sizeof para exibir a quantidade de memória que
os diferentes tipos de matrizes requerem:
|
#include <stdio.h> void main(void) { int notas[100]; float salar[100]; char string[100]; printf("Memoria para conter int notas[100] %d
bytes\n", sizeof(notas)); printf("Memoria para conter float salar[100] %d
bytes\n", sizeof(salar)); printf("Memoria para conter char string[100] %d
bytes\n", sizeof(string)); } |
6.4 - Inicializando uma Matriz
Muitos
programas em Linguagem C inicializam as strings de caracteres como segue:
|
char titulo[] = "UNESP - Ilha
Solteira"; char secao[64] = "Matrizes"; |
No
primeiro caso, o compilador alocará 22 bytes para armazenar a string. No
segundo, o compilador alocará uma matriz de 64 bytes, inicializando os primeiro
8 caracteres com as letras "Matrizes" e o caracter NULL. A maioria
dos compiladores também inicializará as posições de bytes restantes com NULL.
Quando declara-se matrizes de outros tipos, pode inicializar matrizes da mesma
forma. Por exemplo, o comando a seguir inicializa a matriz de inteiros notas com os valores 80, 70, 90, 85
e 80:
|
int notas[5] = {80, 70, 90, 85, 80}; |
Quando
atribui-se valores iniciais a uma matriz, é necessário delimitar os valores por
abre e fecha chaves ( {} ). No caso anterior, o tamanho da matriz é igual ao
número de valores atribuídos. O comando a seguir, no entanto, atribui quatro
valores de ponto flutuante a uma matriz que pode armazenar 64 valores:
|
float salar[64] = {25000.0, 32000.0; 44000.0, 23000.0}; |
Dependendo
do compilador, ele pode atribuir 0 aos elementos aos quais o programa não
atribui valores explícitos. No entanto, como regra, não se deve assumir que o
compilador inicializará os outros elementos. Além disso, se não for
especificado um tamanho de matriz, o compilador alocará memória suficiente para
conter somente os valores que você especificar. Por exemplo, a seguinte
declaração de matriz cria uma matriz grande o suficiente para conter três
valores do tipo long:
|
long planetas[] =
{1234567L, 654321L, 1221311L}; |
6.5 –
Acessando Elementos da Matriz
Os
valores armazenados em uma matriz são chamados elementos de matriz. Para
acessar um elemento da matriz, você especifica o nome da matriz e o elemento
que deseja. O programa a seguir, inicializa a matriz notas e depois usa printf para exibir os valores dos elementos:
|
#include <stdio.h> void main(void) { int notas[5] = {80, 70,
90, 85, 80}; printf("Valores da
Matriz\n"); printf("notas[0]
%d\n", notas[0]); printf("notas[1]
%d\n", notas[1]); printf("notas[2]
%d\n", notas[2]); printf("notas[3]
%d\n", notas[3]); printf("notas[4]
%d\n", notas[4]); } |
6.6 – Percorrendo em um Laço Elementos da Matriz
Quando
se referencia muitos elementos de uma matriz, especificar números para cada
elemento da matriz individualmente pode ser demorado e tedioso. Como uma
alternativa, os programas podem usar uma variável para referenciar os elementos
da matriz. Por exemplo, assumindo que a variável i contenha o valor 2, o
comando a seguir atribuiria o valor 80 a matriz[2]:
|
i = 2; matriz[i] = 80; |
O
código a seguir usa a variável i e um laço for para
exibir os elementos da matriz notas:
|
#include <stdio.h> void main(void) { int notas[5] = {80, 70, 90, 85, 80}; int i; printf("Valores da Matriz\n"); for (i = 0; i < 5; i++) printf("notas[%d] %d\n", i, notas[i]); } |
6.7 – Usando Constantes Para Definir as Matrizes
Como
visto, quando os programas trabalham com matrizes, é necessário especificar o
tamanho da matriz. Por exemplo, o programa a seguir declara uma matriz de cinco
valores e depois usa um laço for para exibir os valores da matriz:
|
#include <stdio.h> void main(void) { int valores[5] = {80, 70, 90, 85, 80}; int i; for (i = 0; i < 5; i++)
printf("valores[%d] %d\n", i, valores[i]); } |
Por
exemplo, suponha que seja necessário alterar o código anterior de tal forma que
ele suporte 10 valores. Precisará alterar não somente a declaração da matriz,
mas também o laço for. Quanto mais alterações forem feitas em um programa,
maiores as chances de errar. O programa a seguir declara uma matriz com base na
constante TAM_MATRIZ. Como se vê, o programa não somente usa a constante para
declarar a matriz, mas também usa a constante como a condição final para o laço
for:
|
#include <stdio.h> #define TAM_MATRIZ 5 void main(void) { int valores[TAM_MATRIZ] =
{80, 70, 90, 85, 80}; int i; for (i = 0; i <
TAM_MATRIZ; i++)
printf("valores[%d] %d\n", i, valores[i]); } |
Se mais tarde for necessário alterar o tamanho da
matriz, poderá alterar o valor atribuído à constante TAM_MATRIZ para que o
programa automaticamente atualize os laços que controlam a matriz como o
tamanho da matriz.
6.8 – Passando uma Matriz a uma Função
Quando
declara-se uma função que trabalha com um parâmetro matriz, precisa informar o
compilador. Por exemplo, o seguinte programa usa a função exibe_matriz
para exibir os valores em uma matriz. Como pode-se ver, o programa passa para a
função tanto a matriz como o número de elementos que a matriz contém, como
mostrado a seguir:
|
#include <stdio.h> void exibe_matriz(int valores[], int num_de_elementos) { int i; for (i = 0; i <
num_de_elementos; i++)
printf("%d\n", valores[i]); } void main(void) { int notas[5] = {70, 80,
90, 100, 90}; exibe_matriz(notas, 5); } |
Quando
uma função recebe uma matriz como parâmetro, o programa não precisa especificar
o tamanho da matriz na declaração do parâmetro. No caso da função exibe_valores, os colchetes após o
nome da variável valor
informam o compilador de que o parâmetro é uma matriz. Sabendo que o parâmetro
é uma matriz, o compilador não se preocupa com o tamanho da matriz que o
programa passa para a função.
6.9 – Revisitando as Matrizes Como Funções
No
item anterior, foi visto que ao declarar o parâmetro formal para uma matriz,
não é necessário declarar o tamanho da matriz. Em vez disso, pode-se
especificar somente o abre e fecha colchetes. O programa a seguir passa três
matrizes diferentes (de diferentes tamanhos) para a função exibe_valores:
|
#include <stdio.h> void exibe_matriz(int valores[], int num_de_elementos) { int i; printf("Prestes a
exibir %d valores\n",num_de_elementos); for (i = 0; i <
num_de_elementos; i++)
printf("%d\n", valores[i]); } void main(void) { int notas[5] = {70, 80, 90, 100, 90}; int conta[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int pequeno[2] = {-33,
-44}; exibe_matriz(notas, 5); exibe_matriz(conta, 10); exibe_matriz(pequeno, 2); } |
6.10 – Compreendendo Como as Matrizes de String
Diferem
Muitos
programas passam string para funções. Em muitos casos, as funções não
especificaram o tamanho da string. Por exemplo, o comando a seguir usa a função
strupr para converter uma string para maiúsculas:
|
char titulo[64] = "Unesp Ilha
Solteira"; strupr(titulo); |
Como
foi visto, na Linguagem C o caracter NULL representa o final de uma string de
caracteres. Portanto, as funções podem procurar o caracter NULL nos elementos
da matriz para determinar onde a matriz termina. No entanto, as matrizes de
outros tipos, tais como int, float ou long, não tem um caracter finalizador
equivalente. Portanto, você normalmente precisa passar para as funções que
trabalham com matrizes o número de elementos que a matriz contém.
6.11 – Determinando Quantos Elementos Uma Matriz
Pode Armazenar
Já
foi visto anteriormente que, dependendo do tipo de uma matriz, a quantidade
real de memória que uma matriz pode consumir diferirá. Se o ambiente de
trabalho for o DOS, a quantidade de memória que as matrizes podem consumir
dependerá do modelo de memória atual. Em geral, uma matriz não pode consumir
mais do que 64Kb de espaço. O programa a seguir pode não passar na compilação
porque as matrizes consomem muita memória:
|
void main(void) { char string[66000L];
/* 66,000 bytes */ int values[33000L];
/* 33,000 * 2 = 66,000 bytes */ float numbers[17000];
/* 17,000 * 4 = 68,000 bytes */ } |
6.12 – Compreendendo as Matrizes Multidimensionais
Como
foi visto, uma matriz é uma variável que pode armazenar múltiplos valores do
mesmo tipo. Em todos os exemplos apresentados até o momento, as matrizes
consistiram de uma fileira de dados. No entanto, a Linguagem C permite matrizes
bi, tri e multidimensionais. O melhor
modo de visualizar uma matriz bidimensional é com uma tabela com linhas e
colunas. Se uma matriz contém três dimensões, visualize-a como várias páginas,
cada uma das quais contendo uma tabela bidimensional.
Por
exemplo, ao declarar-se uma matriz bidimensional, o primeiro valor que for
especificado informará o número de linhas, e o segundo valor, o número de
colunas:
|
int tabela [2] [3]; |
6.13 - Inicializando Elementos em Uma Matriz
Bidimensional
No
item 5.4 foi visto que, para inicializar elementos de matriz, você pode colocar
os valores do elemento dentro de abre e fecha colchetes após a declaração da
matriz. O comando a seguir usa a mesma técnica para inicializar uma matriz
bidimensional. No entanto, neste caso, o comando especifica os valores para
cada linha da matriz dentro de chaves:
|
int tabela [2] [3] = {{1,2,3}, {4,5,6}}; |
O
compilador inicializará os elementos da matriz como mostrado a seguir:
|
1 |
2 |
3 |
|
4 |
5 |
6 |
6.14 – Percorrendo em Um Laço Uma Matriz
Bidimensional
Quando
os programas trabalham com matrizes bidimensionais, normalmente usa-se duas
variáveis para acessar elementos da matriz. O programa a seguir usa as
variáveis linha e coluna para exibir os valores
contidos dentro da matriz tabela:
|
#include <stdio.h> void main(void) { int linha, coluna; float tabela[3][5] = {{1.0, 2.0, 3.0, 4.0, 5.0},
{6.0, 7.0, 8.0, 9.0, 10.0},
{11.0, 12.0, 13.0, 14.0, 15.0}}; for (linha = 0; linha
< 3; linha++) for (coluna = 0; coluna
< 5; coluna++)
printf("tabela[%d][%d] = %f\n", linha, coluna,
tabela[linha][coluna]); } |
Colocando
laços for um dentro do outro, como mostrado, o programa exibirá os elementos
contidos na primeira linha da matriz (1.0 até 5.0). Em seguida, o programa irá
se mover para a próxima linha, e, depois, para a terceira linha, exibindo os
elementos dentro de cada linha.
6.15 – Percorrendo Uma Matriz Tridimensional
No
item anterior foi visto como percorrer uma matriz bidimensional usando duas variáveis
chamadas linha e coluna. O programa a seguir usa as variáveis linha,
coluna e tabela para percorrer uma matriz
tridimensional:
|
#include <stdio.h> void main(void) { int linha, coluna,
tabela; float valores[2][3][5] =
{ {{1.0, 2.0, 3.0, 4.0,
5.0}, {6.0,
7.0, 8.0, 9.0, 10.0}, {11.0,
12.0, 13.0, 14.0, 15.0}},
{{16.0, 17.0, 18.0, 19.0, 20.0},
{21.0, 22.0, 23.0, 24.0, 25.0},
{26.0, 27.0, 28.0, 29.0, 30.0}}
}; for (linha = 0; linha
< 2; linha++) for (coluna = 0; coluna
< 3; coluna++) for (tabela = 0;
tabela < 5; tabela++)
printf("valores[%d][%d][%d] = %f\n", linha, coluna, tabela,
valores[linha][coluna][tabela]); } |
6.16 – Passando uma Matriz Bidimensional Para uma
Função
No
item 5.8, foi visto que, ao passar matrizes para uma função, não será
necessário especificar o número de elementos na matriz. Em matrizes
bidimensionais, não será necessário especificar o número de linha na matriz,
mas, sim, especificar o número de colunas. O programa a seguir usa a função exibe_2d_matriz para exibir o
conteúdo de variáveis matrizes bidimensionais:
|
#include <stdio.h> void exibe_2d_matriz(int matriz[][10], int linhas) { int i, j; for (i = 0; i < linhas; i++) for (j = 0; j < 10;
j++) printf("matriz[%d][%d]
= %d\n", i, j, matriz[i][j]); } void main(void) { int a[1][10] = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; int b[2][10] = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {11, 12,
13, 14, 15, 16, 17, 18, 19,20}}; int c[3][10] = {{1, 2, 3,
4, 5, 6, 7, 8, 9, 10}, {11, 12,
13, 14, 15, 16, 17, 18, 19, 20}, {21, 22,
23, 24, 25, 26, 27, 28, 29, 30}}; exibe_2d_matriz(a, 1); exibe_2d_matriz(b, 2); exibe_2d_matriz(c, 3); } |
6.17 – Tratando as Matrizes Multidimensionais Como
Uma Dimensão
Quando
for necessário trabalhar com os elementos de uma matriz multidimensional, mas
sem precisar acessar os elementos em suas posições de linha ou coluna, as
funções poderão tratar a matriz multidimensional como se ela tivesse uma
dimensão. O programa a seguir retorna a soma dos valores em uma matriz
bidimensional:
|
#include <stdio.h> long soma_matriz(int matriz[], int elementos) { long soma = 0; int i; for (i = 0; i < elementos; i++) soma += matriz[i]; return(soma); } void main(void) { int a[10] = {1,
2, 3, 4, 5, 6, 7, 8, 9, 10}; int b[2][10]={{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {11, 12, 13,
14, 15, 16, 17, 18, 19,20}}; int c[3][10]={{1, 2, 3,
4, 5, 6, 7, 8, 9, 10}, {11, 12, 13,
14, 15, 16, 17, 18, 19, 20}, {21, 22, 23,
24, 25, 26, 27, 28, 29,30}}; printf("Soma dos
elementos da primeira matriz %d\n", soma_matriz(a, 10)); printf("Soma dos
elementos da segunda matriz %d\n", soma_matriz(b, 20)); printf("Soma dos
elementos da terceira matriz %d\n", soma_matriz(c, 30)); } |
6.18 – Síntese do Módulo
É apresentado à seguir, uma síntese do que foi tratado em cada item deste módulo. Com esta síntese você poderá relembrar conceitos vistos durante nosso estudo ou mesmo direcionar seu estudo, caso você já tenha conhecimentos na Linguagem C.
·
6.1 – Compreendendo as Matrizes: é dada uma explicação
que uma matriz é uma estrutura de dados que pode armazenar múltiplos
valores do mesmo tipo.
·
6.2 – Declarando uma Matriz: neste item é visto como declarar uma matriz,
precisando-se especificar o tipo desejado (tal como int, float ou double), bem
como o tamanho da matriz.
·
6.3 – Compreendendo os Requisitos de
Armazenamento de uma Matriz: foi
visto que ao declarar uma matriz, o compilador aloca memória suficiente
para conter o número de valores especificado. A quantidade real de memória que
o compilador aloca depende do tipo da matriz.
·
6.4 – Inicializando uma Matriz: neste item é explicada de maneira clara como
inicializar diferentes tipos de matrizes.
·
6.5 – Acessando Elementos da Matriz: foi visto que para acessar um elemento
da matriz, você especifica o nome da matriz e o elemento que deseja.
·
6.6 – Percorrendo em um Laço Elementos da
Matriz: foi mostrado que quando se referencia muitos elementos
de uma matriz, especificar números para cada elemento da matriz individualmente
pode ser demorado e tedioso. Como uma alternativa, os programas podem usar uma
variável para referenciar os elementos da matriz.
·
6.7 – Usando Constantes Para Definir as
Matrizes: mostra como os programas
usam constantes para definir matrizes.
·
6.8 – Passando uma Matriz a uma Função: é
visto que programas passam para a função tanto a matriz como o número de
elementos que a matriz contém.
·
6.9 – Revisitando as Matrizes Como
Funções: . foi visto um programa que passa três matrizes diferentes (de
diferentes tamanhos) para a função exibe_valores.
·
6.10 – Compreendendo Como as Matrizes de
String Diferem: explica as
principais diferenças das matrizes de string.
·
6.11 – Determinando Quantos Elementos Uma
Matriz Pode Armazenar: foi visto que se o ambiente de trabalho for o DOS, a
quantidade de memória que as matrizes podem consumir dependerá do modelo de
memória atual. Em geral, uma matriz não pode consumir mais do que 64Kb de
espaço.
·
6.12 – Compreendendo as Matrizes
Multidimensionais: foi visto que a Linguagem C permite matrizes bi, tri
e multidimensionais.
·
6.13 – Inicializando Elementos em Uma
Matriz Bidimensional: foi mostrado
como inicializar uma matriz bidimensional.
·
6.14 – Percorrendo em Um Laço Uma Matriz
Bidimensional: foi mostrado um programa que usa as variáveis linha e coluna
para exibir os valores contidos dentro da matriz tabela.
·
6.15 – Percorrendo Uma Matriz
Tridimensional: foi mostrado um programa que usa as variáveis linha, coluna
e tabela para percorrer uma matriz tridimensional.
· 6.16 – Passando uma Matriz Bidimensional Para uma Função: foi visto que para passar matrizes bidimensionais para uma função, não será necessário especificar o número de linha na matriz, mas, sim, especificar o número de colunas.
· 6.17 – Tratando as Matrizes Multidimensionais Como Uma Dimensão: foi visto que quando for necessário trabalhar com os elementos de uma matriz multidimensional, mas sem precisar acessar os elementos em suas posições de linha ou coluna, as funções poderão tratar a matriz multidimensional como se ela tivesse uma dimensão.