7. Vetores e Matrizes

7.1 Vetores

Vetores são variáveis com capacidade para armazenar diferentes valores do mesmo tipo sequencialmente na memória. São úteis em diversos contextos de programação quando se deseja armazenar vários valores do mesmo tipo, por exemplo, considere um programa que peça ao usuário para digitar a nota de 40 alunos e as armazene na memória. Sem a utilização de vetores seria necessário declarar 40 variáveis, uma para armazenar cada nota, atribuindo-lhes os valores digitados pelo usuário. Este mesmo programa poderia ser feito declarando apenas 1 vetor que armazene 40 valores, facilitando a manipulação das informações no programa.

  • Definição formal: Vetor é uma variável composta homogênea unidimensional formada por uma sequência de células do mesmo tipo, com um mesmo identificador (nome da variável) e alocadas sequencialmente na memória.

7.1.1 Declaração de vetores

A declaração de um vetor se assemelha à declaração de variáveis simples (armazenam apenas um valor), conforme ilustrado na tabela acima. Entre os tipos_de_dados disponíveis para a declaração estão {int, float, double, char, bool, string}, além disto o nome de um vetor deve seguir as regras de declaração de variáveis (sem caracteres especiais, espaços, etc). O que diferencia a declaração de um vetor de uma variável simples é a especificação do número de células a serem armazenadas, que devem estar após o nome do vetor entre colchetes. Observe que o tamanho de um vetor pode ser determinado por uma variável inteira, como na última linha do exemplo abaixo.

Exemplos de declaração de vetores em C++

int codigo[40];  //Declara o vetor codigo que armazena 40 células do tipo int
float preco[6];  //Declara o vetor preco que armazena 6 células do tipo float
char alternativa[10]; //Declara o vetor alternativa que armazena 10 células do tipo char
int n = 50;
int nota[n];  //Declara o vetor nota que armazena 50 células do tipo int

Como as células dos vetores são armazenadas sequencialmente na memória, a seguinte declaração

  • float preco[6];

será representada na memória da seguinte forma:

fig1.png

Sendo armazenada uma única variável com o nome preco com 6 posições (células), nas quais podem ser armazenados números reais. Nas linguagens C/C++ a primeira célula de um vetor será sempre indexada pelo índice 0, portanto, ao declarar um vetor de N células, estas serão armazenadas na memória sob os índices 0,…, (N-1).

Assim como as variáveis simples, valores podem ser atribuídos às células dos vetores assim que estes são declarados. Desta forma, a seguinte declaração cria um vetor de 6 células e simultaneamente atribui valores à elas.

  • float preco[6] = {9.1, 4.5, 75.3, 84, 19.2, 1.88};

O vetor resultante na memória seria

fig2.png

7.1.2 Acesso aos elementos do vetor

Para atribuir ou recuperar valores das células de um vetor, basta informar o seu nome e o índice da célula que deseja acessar entre colchetes. Tomando como exemplo a declaração acima do vetor preco, para mostrar na tela o segundo valor deve-se usar o seguinte código:

cout << preco[1] << endl;

De maneira análoga é realizada a atribuição de valores às células do vetor. O código abaixo insere os valores 31.7 e 7.98 nas células 1 e 5 do vetor preco, respectivamente.

preco[1] = 31.7;
preco[5] = 7.98;
fig3.png

Vale lembrar que apenas uma célula pode ser acessada por comando. Logo, comandos para manipular mais de uma célula ao mesmo tempo gerarão erros de compilação. Por exemplo, qualquer um dos três comandos abaixo geraria um erro de compilação:

preco[0][3] = 10;                         //Erro!
cout << preco << endl;                     //Erro!
cout << preco[0][1][2][3][4][5][6] << endl;    //Erro!

Um dos principais benefícios dos vetores é a indexação de suas células em estruturas de repetição. Assim, independente de seu tamanho, apenas um comando é suficiente para que todas as suas células sejam acessadas. Veja no exemplo abaixo como todos os valores de um vetor podem ser exibidos na tela usando a indexação em laços de repetição:

#include <iostream>
using namespace std;
 
int main()
{
    for (int i = 0; i < 8; i++)
    {
        cout << preco[i] << " ";
    }
}

Uma possível execução do código acima é mostrada abaixo:

Digite a quantidade de notas: 8
Insira o valor da 1a. nota: 90
Insira o valor da 2a. nota: 34
Insira o valor da 3a. nota: 56
Insira o valor da 4a. nota: 29
Insira o valor da 5a. nota: 8
Insira o valor da 6a. nota: 96
Insira o valor da 7a. nota: 72
Insira o valor da 8a. nota: 48

Considerando a execução acima e pelas entradas informadas pelo teclado, a estrutura do vetor na memória seria a seguinte:

fig4.png

7.1.3 Vetores e Funções

Assim como as demais variáveis, os vetores também podem ser passados como parâmetros para as funções. Para indicar que um parâmetro é um vetor, basta incluir o tamanho deste vetor entre colchetes após o seu nome. Por exemplo, considere a função abaixo que recebe como parâmetro um vetor de 10 inteiros e retorna o maior elemento deste vetor:

int maior (int vet[10])
{
    int m = vet[0];
    for (int i = 1; i < 10; ++i)
    {
        if (vet[i] > m) m = vet[i];
    }
    return m;
}

Em alguns casos, o tamanho do vetor a ser passado como parâmetro não é conhecido durante a implementação da função, para passar o vetor como parâmetro nestes casos basta omitir o tamanho deste vetor e incluir apenas os símbolos [ ] (abre e fecha colchetes) após o nome do parâmetro. Nestes casos, recomenda-se que o tamanho do vetor seja passado como um outro argumento, do tipo inteiro, conforme mostra o exemplo abaixo, que generaliza a função maior para vetores de tamanhos quaisquer.

int maior (int vet[], int tam)
{
    int m = vet[0];
    for (int i = 1; i < tam; ++i)
    {
        if (vet[i] > m) m = vet[i];
    }
    return m;
}

Para invocar a função que tenha um vetor como parâmetro, deve-se informar apenas o nome do vetor na função, não sendo necessárias informações sobre o seu tamanho ou mesmo os símbolos de colchetes.

int main()
{
    int valores [6] = {3, -1, 8, 12, 5, -6};
    int mValor = maior(valores, 6);
    cout << “Maior valor = ” << mValor << endl;
}

Por definição, ao passar um vetor como parâmetro para uma função em C++, esta passagem é feita apenas por referência, ou seja, qualquer alteração nas células deste vetor continuará sendo válida após o término da função. Por este motivo, considere que o símbolo '&' está implícito em todas as passagens de vetores como parâmetros (incluir este símbolo causa um erro de compilação).

#include <iostream>
using namespace std;
 
void zerar(int vet[], int tam)
{
    for (int i = 0; i < tam; ++i) vet[i] = 0;
}
 
int main()
{
    int v[4] = {10, 20, 30, 40};
    cout << "v = [" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << "]" << endl;
    zerar(v, 4);
    cout << "v = [" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << "]" << endl;
}

Ao executar o programa acima o seguinte resultado seria exibido na tela:

v = [10, 20, 30, 40]
v = [0, 0, 0, 0]

7.1.4 Exercícios

1. Elabore um programa que inicialize 2 vetores de 10 elementos cada com valores inseridos pelo usuário, compute e mostre os vetores resultantes contendo
(a) A interseção dos elementos dos dois vetores
(b) A união dos elementos dos dois vetores
(c) A diferença do primeiro vetor pelo segundo
Obs.: Os elementos dos vetores resultantes não podem ser repetidos.

2. Seja o seguinte programa em C++:

#include <iostream>
using namespace std;
 
int main()
{
    int v1[10], v2[10], v3[10];
    cout << "Digite 10 valores para o primeiro vetor:" << endl;
    for (int i = 0; i < 10; ++i) cin >> v1[i];
 
    cout << "Digite 10 valores para o segundo vetor:" << endl;
    for (int i = 0; i < 10; ++i) cin >> v2[i];
 
    for (int i = 0; i < 10; ++i)
    {
        if ( v1[i] > v2[i] ) v3[i] = v1[i];
        else v3[i] = v2[i];
    }
 
    cout << "Valores do terceiro vetor:" << endl;
    for (int i = 0; i < 10; ++i) cout << v3[i] << endl;
}

(a) Quais valores seriam impressos para o terceiro vetor, caso os valores de entrada para os vetores 1 e 2 fossem respectivamente { 7, 3, 12, -6, 19, 11, 6, 4, 0, 21 } e { 12, -16, 14, 3, 8, 11, 51, -1, 20, 2 }?
(b) Descreva a funcionalidade do programa acima.

3. Faça um programa em C++ que inicialize um vetor de 10 posições com valores inseridos pelo usuário no intervalo [0, 9] (seu programa deverá validar os dados digitados pelo usuário), calcule e mostre
(a) O maior elemento do vetor.
(b) Um vetor resultante dividindo-se os elementos do vetor preenchido pelo usuário pelo maior elemento do vetor.

4. Faça um programa onde o usuário digite uma quantidade de valores N que serão armazenados em um vetor (N deve ser definido pelo usuário). Seu programa deve então inverter a ordem destes valores no vetor e depois imprimi-lo na ordem inversa. Por exemplo, suponha que o usuário tenha definido N=5 e digitado os valores { 2, 5, 7, 1, 4 } para preencher o vetor, ou seja, vetor[0] = 2, vetor[1] = 5, vetor[2] = 7, vetor[3] = 1 e vetor[4] = 4. Seu programa deve inverter os valores de modo a obter vetor[0] = 4, vetor[1] = 1, vetor[2] = 7, vetor[3] = 5 e vetor[4] = 2, e mostrar o vetor invertido.

5. Elabore um programa em C++ que peça ao usuário para inserir a temperatura dos últimos N dias (N deve ser definido pelo usuário) e calcule a temperatura média e o desvio padrão da média considerando as informações inseridas pelo usuário.
Obs.: Supondo que a média de um conjunto de N valores seja m, o desvio padrão é dado pela expressão abaixo (onde vi é o valor de temperatura no dia i)

(1)
\begin{align} \sqrt{\frac{\sum\limits_{i=1}^{N}{(v_i - m)^2}}{N-1}} \end{align}

6. Faça um programa onde o usuário insira 20 valores a serem armazenados em um vetor, e depois apresente o seguinte menu de opções ao usuário

  1. Saber em qual célula está armazenado um valor qualquer no vetor
  2. Alterar o valor de alguma célula
  3. Imprimir o vetor
  4. Sair

Obs.: O programa deve apresentar este menu e realizar a operação desejada até que o usuário digite a opção 4.

7. Faça uma função em C++ que receba 4 parametros: um vetor de inteiros, o seu tamanho, um número inteiro A delimitando o início de um intervalo e outro número B delimitando o fim deste intervalo. Esta função deverá retornar verdadeiro caso todos os elementos do vetor pertençam ao intervalo [A, B] ou falso caso contrário. Implemente uma função int main( ) para testar a função acima.

8. Faça uma função em C++ que receba dois parâmetros: um vetor de números inteiros e o seu tamanho, e retorne por referência o maior e o segundo maior elemento deste vetor. Implemente também uma função int main( ) para testar a função acima, pedindo ao usuário para preencher os valores do vetor, invocando a função e mostrando os valores dos elementos retornados por referência.

9. Faça uma função em C++ que receba dois parâmetros: um vetor de números inteiros e o seu tamanho, e modifique a ordem dos elementos deste vetor (caso necessário) para que eles fiquem ordenados em ordem crescente. Use uma função int main( )

10. Faça um programa que preencha um vetor com 100 números aleatórios (entre 0 e 99) e depois imprima todos aqueles valores que forem acima de 50 e sua respectiva posição no vetor (célula onde está armazenado).
Obs.: Inclua a biblioteca stdlib.h para usar a função rand( ) que gera um número aleatório positivo qualquer. A partir daí, basta usar o operador % (resto da divisão) para garantir que o número aleatório esteja no intervalo [0, 99].

7.2 Matrizes

As matrizes generalizam a funcionalidade dos vetores permitindo a declaração de variáveis em um arranjo bidimensional definido por linhas e colunas. Em uma matriz com m linhas e n colunas são criadas m x n células, todas com a capacidade de armazenar dados do mesmo tipo.

  • Definição formal: Uma matriz é uma variável composta homogênea bidimensional formada por uma sequência de células, todas com o mesmo tipo, com o mesmo identificador (nome de variável) e alocadas sequencialmente na memória. O que distingue os valores armazenados por uma matriz são os índices de sua localização na estrutura. Para a identificação de tais valores, usa-se um mapeamento por linhas e colunas indicados entre colchetes [ ].

Como exemplo da aplicação de matrizes, suponha que deseja-se fazer um mapa de sala das turmas de uma escola. Em cada sala existem 6 filas cada uma com 5 mesas, totalizando uma capacidade de acomodar 30 alunos. Para representar este arranjo em um programa, seria possível utilizar uma matriz de 5 linhas e 6 colunas, definindo 30 células cada uma podendo armazenar o nome de um aluno.

fig5.png

7.2.1 Declaração de matrizes

Ao declarar uma matriz será necessário informar além do tipo de dados a ser armazenado em suas células, a quantidade de linhas e de colunas que definirá o arranjo. Os possíveis tipos de dados são {int, float, double, char, bool, string} e as dimensões de linhas e colunas devem ser delimitadas por [ ] após o nome da matriz. A seguir está a sintaxe básica de declaração de uma matriz

  • tipo_de_dados nome_da_variavel [quantidade_de_linhas][quantidade_de_colunas];

Exemplos de declaração de matrizes

int notas[10][20]; //Declara uma matriz de 200 células (dispostas em 10 linhas e 20 colunas) para armazenar números inteiros
float medidas[8][8]; //Declara uma matriz de 64 células (dispostas em 8 linhas e 8 colunas) para armazenar números reais
int l=20, c=10;
char posicoes[l][c]; //Matriz para armazenar 200 caracteres em 20 linhas e 10 colunas

As matrizes são alocadas sequencialmente na memória, sendo que suas células devem ser acessadas referenciando-se uma linha e uma coluna. A seguinte declaração

  • int mat[3][3];

aloca a seguinte matriz na memória (observe que assim como os vetores, as matrizes têm o seu primeiro índice de linha e coluna iniciados em 0):

fig6.png

É possível também fazer a inicialização das células da matriz ao declará-la. Para isto, basta na declaração que se explicite o valor de todas as suas células. Isto é feito usando-se o código:

  • int mat[3][3] = {8, 3, 6, 7, 1, 4, 2, 5, 9};
fig7.png

A inicialização das matrizes também pode ser feita através da leitura do teclado, permitindo que o usuário atribua valores às suas células, conforme ilustra o exemplo:

#include <iostream>
using namespace std;
 
int main()
{
    int mat[3][3];
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3;j++)
        {
            cout<< "Insira o valor do elemento da " << i+1 << "a. linha, " << j+1 << "a. coluna: ";
            cin >> mat[i][j];
        }
    }
}
Insira o valor do elemento da 1a. linha, 1a. coluna: 12
Insira o valor do elemento da 1a. linha, 2a. coluna: 59
Insira o valor do elemento da 1a. linha, 3a. coluna: 7
Insira o valor do elemento da 2a. linha, 1a. coluna: 76
Insira o valor do elemento da 2a. linha, 2a. coluna: 55
Insira o valor do elemento da 2a. linha, 3a. coluna: 42
Insira o valor do elemento da 3a. linha, 1a. coluna: 17
Insira o valor do elemento da 3a. linha, 2a. coluna: 66
Insira o valor do elemento da 3a. linha, 3a. coluna: 80
fig8.png

7.2.2 Acesso aos elementos de uma matriz

Uma vez que as células da matriz estão dispostas em linhas e colunas, para acessar o conteúdo de uma célula é necessário especificar a qual linha e coluna da matriz a célula está associada. Para isto, basta usar o nome da matriz seguido pelos índices da linha e da coluna (entre colchetes) , como no exemplo de escrita nas células:

mat[2][0] = 31;
mat[1][2] = 15;
mat[0][2] = -7;
fig9.png

7.2.3 Exemplos de manipulação de matrizes

As matrizes são a base de muitos procedimentos para manipulação e processamento de imagens em computação, além de serem um poderoso instrumento matemático na solução de sistemas lineares, entre outros.

O programa a seguir pede ao usuário que preencha uma matriz 3x3 (3 linhas e 3 colunas) e imprime na tela a soma dos elementos que compõem a diagonal principal desta matriz.

#include <iostream>
using namespace std;
int main()
{
    int mat[3][3], i, j, s;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout<< "Insira o elemento da " << i+1 << "ª linha, " << j+1 << "ª coluna: ";
            cin >> mat[i][j];
        }
    }
    s = 0;
    for (i = 0; i < 3; i++){
        s += mat[i][i];
    }
    cout << "Soma dos elementos da diagonal principal = " << s << endl;
}

O próximo exemplo mostra um programa que calcula a soma de matrizes (mat3 = mat1 + mat2), onde mat1 e mat2 são duas matrizes 3x3 que contém valores inseridos pelo usuário e mat3 também é uma matriz 3x3 resultante da soma das duas anteriores. Obs.: A soma de duas matrizes é dada pela soma dos valores armazenados nas células que têm a mesma posição: mat3[i][j] = mat1[i][j] + mat2[i][j].

#include <iostream>
using namespace std;
int main() {
    int mat1[3][3], mat2[3][3], mat3[3][3];
 
    cout << "Preencha a matriz 1" << endl;
    for (int i = 0; i <= 2; i++)
    {
        for (int j = 0; j <= 2;j++)
        {
            cout << "Insira o elemento da " << i+1 << "ª linha, " << j+1 << "ª coluna: ";
            cin >> mat1[i][j];
        }
    }
 
    cout << "Preencha a matriz 2" << endl;
    for (int i = 0; i <= 2; i++)
    {
        for (int j = 0; j <= 2;j++)
        {
            cout << "Insira o elemento da " << i+1 << "ª linha, " << j+1 << "ª coluna: ";
            cin >> mat2[i][j];
        }
    }
 
    for (int i = 0; i <= 2; i++)
    {
        for (int j = 0; j <= 2; j++)
        {
            mat3[i][j] = mat1[i][j] + mat2[i][j];
        }
    }
 
    cout << "Matriz resultante" << endl;
    for (int i = 0; i <= 2; i++)
    {
        for (int j = 0; j <= 2; j++)
        {
            cout<< "mat3[" << i+1 << "][" << j+1 << "] = " << mat3[i][j] << endl;
        }
    }
}

7.2.4 Matrizes e Funções

Assim como os vetores, matrizes também podem ser passadas como parâmetros para as funções. Isto permite que operações a serem realizadas em matrizes sejam realizadas dentro das funções, organizando e permitindo o reaproveitamento do código. Uma matriz é passada como parâmetro a uma função incluindo o seu tipo, nome e dimensões (número de linhas e número de colunas) no cabeçalho da função. A função a seguir recebe uma matriz de 5 linhas e 5 colunas como parâmetro e retorna o maior elemento desta matriz.

float retornaMaior(float mat[5][5])
{
    int maior = mat[[0][0];
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            if (mat[i][j] > maior) maior = mat[i][j];
        }
    }
    return maior;
}

As células das matrizes também são implicitamente passadas como referência às funções, o que significa que o símbolo de referência '&' está implícito em cada matriz passada como parâmetro e não deve ser explicitamente usado. Como consequência, qualquer modificação feita nas células de uma matriz dentro de uma função permanecerá mesmo depois que esta função terminar sua execução. O exemplo a seguir mostra um programa que usa uma função para multiplicar os valores de uma matriz por um escalar k. Observe que ao chamar a função, apenas o nome da matriz é usado, enquanto que na declaração é necessário incluir suas dimensões.

#include <iostream>
using namespace std;
 
void multiplica(float mat[5][5], float k)
{
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            mat[i][j] = k * mat[i][j];
        }
    }
}
 
int main()
{
    float k, valores[5][5];
    cout << "Preencha os valores da matriz:" << endl;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            cout << "Digite um valor para o elemento da linha " << i << ", coluna " << j << ": ";
            cin >> valores[i][j];
        }
    }
    cout << "Digite o valor de uma constante k para multiplicar a matriz: ";
    cin >> k;
 
    multiplica(valores, k);
 
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            cout << valores[i][j] << " ";
        }
        cout << endl;
    }
}

Na linguagem C++ é possível passar matrizes como parâmetro de funções informando suas duas dimensões (linhas e colunas) como no exemplo acima ou informando apenas o seu número de colunas, quando o número de linhas é determinado pelo usuário durante a execução do programa. Caso o cabeçalho de uma função que receba uma matriz como parâmetro seja escrito sem informar o número de colunas desta matriz, será lançado um erro de compilação. As declarações abaixo ilustram as possíveis declarações de matrizes como parâmetros de funções em C++.

void imprimeMatriz1(float mat[5][5]); //OK! Informa-se ambas as dimensões da matriz 
void imprimeMatriz2(float mat[][5]);  //OK! Informa-se apenas o número de colunas da matriz 
void imprimeMatriz3(float mat[5][]); //ERRO! Não foi informado o número de colunas da matriz
void imprimeMatriz4(float mat[][]); //ERRO! Não foi informada nenhuma dimensão da matriz

7.2.5 Exercícios

1. Faça uma função denominada verificaValor que receba uma matriz de inteiros de dimensão 4 x 4 e um número inteiro x qualquer e retorne verdadeiro caso x esteja na matriz e falso caso contrário. Implemente também uma função int main( ) que peça ao usuário para preencher a matriz 4 x 4 de valores e então permita ao usuário digitar valores para verificar se eles estão na matriz, usando a função verificaValor.

2.Faça um programa que carregue uma matriz 10 x 3 com a nota de 10 alunos em 3 provas e então apresente um relatório mostrando para cada aluno (linha da matriz):

  • A maior nota obtida entre as 3 provas;
  • A nota média;

3. Faça um programa que carregue uma matriz com m x n números inteiros (onde m e n são definidos pelo usuário) e mostre quais os elementos desta matriz que se repetem e quantas vezes cada um repete está repetido.

4. Faça uma função denominada somaDiagonal que receba como parâmetro uma matriz 5 x 5 com números reais e retorne a soma dos elementos da diagonal principal desta matriz. Implemente também uma função int main( ) para testar a função somaDiagonal.

5. Faça uma função denominada inverteDiagonal que receba como parâmetro uma matriz 5 x 5 com números reais e troque os elementos da diagonal principal desta matriz pelos elementos da diagonal secundária. Use uma função int main( ) para testar a função inverteDiagonal.

6. Faça um programa que peça ao usuário para preencher uma matriz de valores inteiros de dimensão m x n (onde m e n são definidos pelo usuário) que assegure após preenchida a matriz, não existirão elementos repetidos nela, ou seja, durante a digitação dos valores, caso o usuário digite um valor que já esteja na matriz isto deve ser informado a ele e o valor descartado.

7. Faça um programa que peça ao usuário para digitar valores para duas matrizes: uma matriz A de dimensão 4 x 3 e outra matriz B de dimensão 3 x 4, ambas armazenando valores reais. Após isto, seu programa deverá mostrar na tela uma terceira matriz C, de dimensões 4 x 4 resultante da multiplicação de A x B.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License