tipo nome[número_de_elementos];
int const dimensão
= 30;
int mi[10]; //
matriz
com 10 int
.
char mc[80]; //
matriz
com 80 char
.
float mf[dimensão]; //
matriz
com 30 float
.
double md[3]; //
matriz
com 3 double
.int n = 50;
int const m = 100;
int matriz_de_inteiros[m]; //
ok,
m
é uma constante.
int matriz_de_inteiros[300]; //
ok,
300 é um valor literal.
int matriz_de_inteiros[n];
//
errado!
n
não é uma constante.int m[10]; //
elementos por inicializar, contêm lixo!
ou
m[6] = 5; //
atribui o inteiro 5 ao 7º elemento da matriz.
Importante: Os índices de uma matriz começam em zero. Na matriz
int a = 6;
m[a] = 5; //
atribui o inteiro 5 ao 7º elemento da matriz.
m
acima o
índice 10 não corresponde a nenhum elemento da matriz!
Número de ordem do elemento | Posição ou índice |
---|---|
1º | 0 |
2º | 1 |
3º | 2 |
4º | 3 |
etc. | etc. |
int m[4] = {10, 20, 0, 0};
int m[] = {10, 20, 0, 0}; //
dimensão
implícita de 4 elementos.
int grande[4] = {1, 2}; //
inicializa os elementos da matriz com 1, 2, 0 e 0.int grande[100] = {}; //
inicializa toda a matriz com 0 (zero).
int m[3][4];
é interpretada como significando int (m[3])[4];
que
significa: "m
é uma matriz com três elementos, cada
um dos quais é uma matriz com quatro elementos do tipo int
".
A indexação destas matrizes faz-se usando tantos índices
quantas as "matrizes dentro de matrizes" (incluindo a exterior), ou seja,
tantos índices quantas as dimensões da matriz. Para
m
conforme definida acima:
m[1][3] =
4; //
atribui
4 ao elemento na linha 1 (2ª linha), coluna 3 (4ª coluna) da
matriz,
//
ou melhor, ao elemento 3 da matriz
que é o elemento 1 da matriz
m
.
int i =
0, j = 1;
m[i][j]
= m[1][3]; //
atribui
4 à posição (0, 1) da matriz.
Importante: O C++ ignora sempre a primeira dimensão de matrizes definidas como parâmetros de uma rotina, sendo necessário usar um parâmetro adicional para indicar esta dimensão (é para isso que é utilizado o parâmetro
int const número_de_colunas = 3;
void multiplicaMatrizPorEscalar(double matriz[][número_de_colunas],
int const número_de_linhas,double const escalar)
{
for(int i = 0; i != número_de_linhas; ++i)
for(int j = 0; j != número_de_colunas; ++j)
matriz[i][j] *= escalar;
}
linhas
). As outras dimensões
têm de ser especificadas por valores constantes (no caso apresentado
a segunda dimensão é indicada pela constante colunas
).
As razões (obscuras) para tão aberrante comportamento serão desvendadas mais
tarde.Importante: Uma matriz é sempre passada por referência ainda que tal não seja indicado no cabeçalho da rotina (isto é uma pequena mentira inofensiva, como se verá mais tarde). Por isso qualquer alteração feita aos valores dos elementos de uma matriz parâmetro de uma rotina tem sempre reflexo na matriz passada como argumento. Se tal for indesejável, pode-se indicar que os elementos da matriz são constantes, o que impedirá a alteração dos valores dos elementos da matriz dentro da rotina. Por exemplo:
int const número_de_linhas = número_de_colunas;
double matriz_identidade[número_de_linhas][número_de_colunas] = {};
//
Inicialização:for(int i = 0; i != número_de_linhas; ++i)
for(int j = 0; j != número_de_colunas; ++j)
if(i == j)
matriz_identidade[i][j] = 1.0;
//
Para multiplicar todos os elementos da matriz por 3,3:multipicaMatrizPorEscalar(matriz_identidade, número_de_linhas, 3.3);
#include <iostream>
#include <iomanip> //
para poder usarsetw
.
using namespace std;
int const número_de_colunas = 3;
void mostraMatriz(int const matriz[][número_de_colunas],
int const número_de_linhas){
for(int i = 0; i != número_de_linhas; ++i) {
for(int j = 0; j != número_de_colunas; ++j)
cout << setw(10) << matriz[i][j];
cout << endl;
}
}
vector
,
que pode substituir com vantagem as matrizes unidimensionais. Esta
classe genérica permite obter novos tipos de dados, ou melhor, classes, representando vectores de itens de um tipo à escolha.
As classes obtidas através da classe genérica vector
têm
várias vantagens em relação às matrizes:
vector
é
necessário adicionar ao topo do programa a linha:
Para definir uma variável que seja um vector é necessário indicar qual o tipo dos seus itens. Por exemplo, para definir um vector
#include <vector> //
assume-se a presença deusing namespace std;
mais à frente.
v
que guarde itens do tipo int
é necessário
dar a instrução:
Neste caso o vector é construído vazio, i.e., com zero itens.
vector<int> v;
Também é possível definir um vector de modo a ter
um determinado número inicial de itens. Por exemplo, pode-se
construir um vector com 10 itens do tipo int
com a seguinte instrução:
Neste caso os 10 itens são inicializados com o valor zero.
vector<int> v(10);
É possível saber qual a dimensão (número
de itens) de um vector utilizando o método size()
(um método
é uma forma especial de rotina), como
no exemplo abaixo:
ou
cout << v.size();
(
vector<int>::size_type dimensão = v.size();
vector<int>::size_type
é sinónimo de um dos
inteiros sem sinal disponível na linguagem C++.)
É possível alterar a dimensão de um vector, quer adicionando
um item ao fim do vector com o método push_back()
quer com o método
v.push_back(novo_item);
resize()
No primeiro caso a dimensão aumenta de uma unidade e o valor passado como argumento é usado para inicializar o novo item construído. No segundo caso a dimensão do vector passará a ser a indicada (20, neste caso).
v.resize(20 /*
nova dimensão*/);
Abaixo pode-se ver um pequeno exemplo de como são construídos dois vectores, preenchidos com 10 valores lidos do teclado e finalmente mostrados no ecrã:
int const dimensão n
= 10;
//
Construção
de um vector de dimensão zero:
vector<int> v;
//
Preenchimento de um
vector por acrescento de itens:
for(int i = 0; i != dimensão;
++i) {
cout <<
"Introduza o valor do item " << i << ": ";
int valor;
cin >> valor;
v.push_back(valor);
}
//
Construção
de um vector de dimensão inicial 10 (10 itens com valor zero):
vector<int> w(dimensão);
//
Alteração
dos itens do vector para valores lidos do teclado:
for(vector<int>::size_type
i = 0; i != w.size(); ++i) {
cout
<< "Introduza o valor do item " << i << ": ";
cin
>> w[i];
}
//
Visualização
no ecrã os valores contidos no vector v
:
for(vector<int>::size_type
i = 0; i != v.size(); ++i)
cout <<
v[i] << " ";
cout << endl;
//
Visualização
no ecrã os valores contidos no vector w
:
for(vector<int>::size_type
i = 0; i != w.size(); ++i)
cout <<
w[i] << " ";
cout << endl;
(Esta secção é uma actualização da secção O
tipo string
, do Resumo da Aula
4.)
A biblioteca padrão do C++ disponibiliza um tipo (na realidade uma classe,
como se verá) chamado string
que permite manipular cadeias de
caracteres representando, por exemplo, texto ou palavras. As variáveis
deste tipo no fundo consistem em sequências de variáveis do tipo char
,
às quais se acede através de uma indexação, pois cada variável tem um número
de ordem na sequência.
Para definir uma variável deste tipo (da classe string
)
é necessário acrescentar ao topo do programa a linha:
A definição de uma variável deste tipo pode ser feita de várias formas. Por exemplo:
#include <string>
string c1("Uma cadeia de caracteres qualquer");
string c2; //
a cadeia fica vazia!
string c3(10, '-');
//
uma cadeia com 10 caracteres '-'.
É possível saber o comprimento da cadeia de caracteres c1
usando a expressão:
Esta expressão é de um tipo aritmético inteiro sem sinal não especificado (i.e., pode ser
c1.length()
unsigned short int
, unsigned
int
ou unsigned long int
, consoante a implementação).
Por isso, a expressão é do tipo string::size_type
, que é sinónimo
de um dos três possíveis tipos referidos.
A uma variável do tipo string
podem-se concatenar caracteres
ou outras cadeias de caracteres:
As cadeias de caracteres são indexáveis, tais como as matrizes clássicas e os vectores. Por exemplo:
c1 += " mais outra..."; //
concatena " mais outra..." ao que já estiver emc1
.string c2(":");
c2 += ')'; //
no fim destas duas instruçõesc2
contém ":)".
Certas rotinas necessitam de ter acesso directo ao conteúdo de uma variável do tipo
string nome("Manel");
nome[0] = 'P';
nome[2] = 'p';
string
na forma de uma cadeia de
caracteres clássica, i.e., de uma matriz de caracteres terminada
de uma forma especial. Para isso é necessário usar
o método c_str()
.
Este método é particularmente útil para obter um argumento
compatível com os construtores das classes ifstream
e ofstream
,
usadas para estabelecer canais de ligação a ficheiros (e
que serão vistas mais tarde).
string nome_do_ficheiro = "ficheiro.txt";
ifstream canal_de_entrada(nome_do_ficheiro.c_str());