aula 9 matrizes clássicas e vectores em c++ melhor alternativa!

Post on 17-Apr-2015

106 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Aula 9

Matrizes clássicas e vectores em C++

Melhor alternativa!

2003/2004Introdução à Programação2

Ler três inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza três inteiros: "; int a, b, c; cin >> a >> b >> c;

cout << c << endl << b << endl << a << endl; }

Como generalizar para 100, por exemplo?

Para simplificar ignoram-se possíveis erros de extracção!

2003/2004Introdução à Programação3

Adaptação para 100 inteiros

Basta acrescentar 97 variáveis, obviamente…

2003/2004Introdução à Programação4

Ler 100 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 100 inteiros: "; int a1, a2, a3, …, a100; cin >> a1 >> a2 >> a3 >> … >> a100;

cout << a100 << endl << a99 << endl … << a1 << endl; }

Pouco prático…

2003/2004Introdução à Programação5

Ler 100 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 100 inteiros: "; int valores[100];

?}

Matriz de 100 inteiros

2003/2004Introdução à Programação6

Sintaxe

double m[4];

m[2] = 2.2;double x = m[3];

Tipo dos elementosNome da matrizNúmero de

elementos

Indexações

Como uma variável

2003/2004Introdução à Programação7

Organização

double m[4];

m[0]:

?

m: double[4]

m[1]:

?

m[2]:

?

m[3]:

?

Índices:1º elemento: índice 02º elemento: índice 1…nº elemento: índice n-1

2003/2004Introdução à Programação8

Inicialização

double m[4];

Com lixo!

m[0]:

?

m: double[4]

m[1]:

?

m[2]:

?

m[3]:

?

2003/2004Introdução à Programação9

Inicialização explícita

double m[4] = {0.0, 1.1, 2.2, 3.3};

m[0]:

0

m: double[4]

m[1]:

1,1

m[2]:

2,2

m[3]:

3,3

2003/2004Introdução à Programação10

Inicialização implícita (I)

double m[4] = {0.0, 1.1};

m[0]:

0

m: double[4]

m[1]:

1,1

m[2]:

0

m[3]:

0

2003/2004Introdução à Programação11

Inicialização implícita (II)

double m[4] = {};

m[0]:

0

m: double[4]

m[1]:

0

m[2]:

0

m[3]:

0

2003/2004Introdução à Programação12

Problemas das matrizes (I)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva…

2003/2004Introdução à Programação13

Ler 100 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 100 inteiros: "; int valores[100]; cin >> valores[0]; cin >> valores[1]; cin >> valores[2]; …

?}

Absurdo! Por extensão não se ganhou nada!

2003/2004Introdução à Programação14

Ler 100 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 100 inteiros: "; int valores[100]; for(int i = 0; i != 100; ++i) cin >> valores[i];

?}

Extracção dos 100 inteiros e armazenamento na matriz por compreensão

2003/2004Introdução à Programação15

Ler 100 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 100 inteiros: "; int valores[100]; for(int i = 0; i != 100; ++i) cin >> valores[i];

for(int i = 100; i != 0; --i) cout << valores[i - 1] << endl;}

Inserção dos 100 inteiros por ordem inversa

2003/2004Introdução à Programação16

Ler 100 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 100 inteiros: "; int valores[100]; for(int i = 0; i != 100; ++i) cin >> valores[i];

for(int i = 99; i != -1; --i) cout << valores[i] << endl;}

Preferível!

2003/2004Introdução à Programação17

Elementos fictícios

double m[4];

m[0]:

?

m: double[4]

m[1]:

?

m[2]:

?

m[3]:

?

Elemento inicial

m[-1]: m[4]:

?

Elemento final

Primeiro elemento

Último elemento

2003/2004Introdução à Programação18

Ciclos com matrizes

Directo Do primeiro ao elemento final, exclusive

Inverso Do último ao elemento inicial, exclusive

2003/2004Introdução à Programação19

Adaptação para 1000 inteiros

Basta substituir 100 por 1000, obviamente…

2003/2004Introdução à Programação20

Ler 1000 inteiros e escrevê-los por ordem inversa

#include <iostream>

using namespace std;

int main() { cout << "Introduza 1000 inteiros: "; int valores[1000]; for(int i = 0; i != 1000; ++i) cin >> valores[i];

for(int i = 99; i != -1; --i) cout << valores[i] << endl;}

Ops…

2003/2004Introdução à Programação21

Ler 1000 inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int main() { int const número_de_valores = 1000;

cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores]; for(int i = 0; i != número_de_valores; ++i) cin >> valores[i];

for(int i = número_de_valores - 1; i != -1; --i) cout << valores[i] << endl;}

Constante!

2003/2004Introdução à Programação22

Generalização (I)

E se se pretender generalizar a leitura para qualquer número de inteiros, dado pelo utilizador?

Basta usar uma variável, obviamente…

2003/2004Introdução à Programação23

Ler inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int main() { cout << “Introduza o número de valores a ler: “; int número_de_valores; cin >> número_de_valores;

cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores];

…}

Erro! Tem de ser constante!

2003/2004Introdução à Programação24

Ler inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int main() { cout << “Introduza o número de valores a ler: “; int n; cin >> n; int const número_de_valores = n;

cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores];

…}

Erro! Tem de ser constante conhecida pelo compilador!

2003/2004Introdução à Programação25

Problemas das matrizes (II)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador

2003/2004Introdução à Programação26

Ler 1000 inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int main() { int const número_de_valores = 1000;

cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores]; for(int i = 0; i != número_de_valores; ++i) cin >> valores[i];

for(int i = número_de_valores - 1; i != -1; --i) cout << valores[i] << endl;}

2003/2004Introdução à Programação27

Vamos modularizar

Leitura dos valores do teclado Escrita invertida dos valores no ecrã

2003/2004Introdução à Programação28

Ler 1000 inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int main() { int const número_de_valores = 1000;

cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores];

// Leitura…

escreveInvertida(…);}

2003/2004Introdução à Programação29

escreveInvertida()

/** Escreve no ecrã os elementos da matriz passada como argumento começando no último. */void escreveInvertida(…) { … }

2003/2004Introdução à Programação30

E a leitura?

Procedimento, que altera a matriz recebida, preenchendo-a…

…ou função, que devolve uma matriz preenchida?

C++ proíbe devolução de matrizes! Mas era má ideia devolver:

Leitura afecta estado do programa (cin): procedimento

Devolução de valor: função Rotina mista é má ideia!

2003/2004Introdução à Programação31

Problemas das matrizes (III)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador Não se podem devolver

2003/2004Introdução à Programação32

lêPara()

/** Lê do teclado valores inteiros que coloca por ordem nos elementos da matriz passada como argumento. */void lêPara(…) { …}

2003/2004Introdução à Programação33

Passagem de matriz como argumento

lêPara(): passagem por referência escreveInvertida(): passagem por valor

2003/2004Introdução à Programação34

escreveInvertida()

/** Escreve no ecrã os elementos da matriz passada como argumento começando no último. @pre V. @post cout.fail() cout sofreu inserções dos número_de_valores elementos da matriz valores pela sua ordem inversa. */void escreveInvertida(int valores[número_de_valores]) { … }

2003/2004Introdução à Programação35

lêPara()

/** Lê do teclado valores inteiros que coloca por ordem nos elementos da matriz passada como argumento. @pre cin.good() cin permite extracção de número_de_valores inteiros sucessivos. @post cin.fail() cin já não contém os primeiros número_de_valores inteiros que continha inicialmente a matriz valores contém-nos pela mesma ordem. */void lêPara(int valores[número_de_valores]) { … }

Falta dizer que passagem é por referência!

2003/2004Introdução à Programação36

Passagem de matriz como argumento

Sempre por referência! Necessário precaver alterações do argumento

em escreveInvertida()!

Mentira piedosa…Explicação no 2º semestre…(tem a ver com ponteiros)

2003/2004Introdução à Programação37

Problemas das matrizes (IV)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador Não se podem devolver Passagem sempre por referência

(mentirita…)

2003/2004Introdução à Programação38

escreveInvertida()

/** Escreve no ecrã os elementos da matriz passada como argumento começando no último. @pre V. @post cout.fail() cout sofreu inserções dos número_de_valores elementos da matriz valores pela sua ordem inversa. */void escreveInvertida(int const valores[número_de_valores]) { … }

Não é a matriz que é constante! São os seus elementos!

2003/2004Introdução à Programação39

Ler 1000 inteiros e escrevê-los por ordem inversa…

/** … */void lêPara(int valores[número_de_valores]) { … }

/** … */void escreveInvertida(int const valores[número_de_valores]) { … }

int main() { int const número_de_valores = 1000;

…}

Invisível aqui!Invisível aqui!

2003/2004Introdução à Programação40

Ler 1000 inteiros e escrevê-los por ordem inversa…

int const número_de_valores = 1000;

/** … */void lêPara(int valores[número_de_valores]) { … }

/** … */void escreveInvertida(int const valores[número_de_valores]) { … }

int main() { …}

Mas o C++ ignora dimensão de matrizes usadas como parâmetro!(mais uma vez, tem a ver com ponteiros)

Mas o C++ ignora dimensão de matrizes usadas como parâmetro!(mais uma vez, tem a ver com ponteiros)

2003/2004Introdução à Programação41

Problemas das matrizes (V)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador Não se podem devolver Passagem sempre por referência (mentirita…) Dimensão ignorada em parâmetros

2003/2004Introdução à Programação42

Ler 1000 inteiros e escrevê-los por ordem inversa…

int const número_de_valores = 1000;

/** … */void lêPara(int valores[]) { … }

/** … */void escreveInvertida(int const valores[]) { … }

int main() { …}

Dimensão arbitráriaDimensão arbitrária

2003/2004Introdução à Programação43

Em falta

Invocar procedimentos em main() Corpo dos procedimentos

2003/2004Introdução à Programação44

Ler 1000 inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int const número_de_valores = 1000;

int main() { cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores]; lêPara(valores);

escreveInvertida(valores);}

2003/2004Introdução à Programação45

lêPara()

/** Lê do teclado valores inteiros que coloca por ordem nos elementos da matriz passada como argumento. @pre cin.good() cin permite extracção de número_de_valores inteiros sucessivos. @post cin.fail() cin já não contém os primeiros número_de_valores inteiros que continha inicialmente a matriz valores contém-nos pela mesma ordem. */void lêPara(int valores[]) { assert(cin.good());

for(int i = 0; i != número_de_valores; ++i) cin >> valores[i]; }

2003/2004Introdução à Programação46

escreveInvertida()

/** Escreve no ecrã os elementos da matriz passada como argumento começando no último. @pre V. @post cout.fail() cout sofreu inserções dos número_de_valores elementos da matriz valores pela sua ordem inversa. */void escreveInvertida(int const valores[]) { for(int i = número_de_valores - 1; i != -1; --i) cout << valores[i] << endl; }

Ainda constante global!

2003/2004Introdução à Programação47

Ler 1000 inteiros e escrevê-los por ordem inversa#include <iostream>

using namespace std;

int main() { int const número_de_valores = 1000;

cout << "Introduza “ << número_de_valores << “ inteiros: "; int valores[número_de_valores]; lêPara(valores, número_de_valores);

escreveInvertida(valores, número_de_valores);}

Dimensão passada como argumentoDimensão passada como argumento

2003/2004Introdução à Programação48

lêPara()

/** Lê do teclado valores inteiros que coloca por ordem nos elementos da matriz passada como argumento. @pre 0 ≤ número_de_valores número_de_valores ≤ dim(valores) cin.good() cin permite extracção de número_de_valores inteiros sucessivos. @post cin.fail() cin já não contém os primeiros número_de_valores inteiros que continha inicialmente a matriz valores contém-nos pela mesma ordem. */void lêPara(int valores[], int const número_de_valores) { assert(0 <= número_de_valores); assert(cin.good());

for(int i = 0; i != número_de_valores; ++i) cin >> valores[i]; }

Não há forma de saber dimensão de matriz parâmetro!

2003/2004Introdução à Programação49

Problemas das matrizes (VI)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador Não se podem devolver Passagem sempre por referência (mentirita…) Dimensão ignorada em parâmetros Não há forma de saber dimensão de matriz

parâmetro

2003/2004Introdução à Programação50

escreveInvertida()

/** Escreve no ecrã os elementos da matriz passada como argumento começando no último. @pre 0 ≤ número_de_valores número_de_valores ≤ dim(valores). @post cout.fail() cout sofreu inserções dos número_de_valores elementos da matriz valores pela sua ordem inversa. */void escreveInvertida(int const valores[], int const número_de_valores) { assert(0 <= número_de_valores);

for(int i = número_de_valores - 1; i != -1; --i) cout << valores[i] << endl; }

2003/2004Introdução à Programação51

Finalmente uma vantagem!

Procedimentos genéricos Funcionam com matrizes de dimensão

arbitrária Número de valores passado pode ser diferente

da dimensão das matrizes Mas… índices não verificados…

2003/2004Introdução à Programação52

Indexação fora dos limites (I)

int a = 0;int m[3] = {0, 1, 2};int b = 0;

m[-1] = -1;m[3] = 3;

cout << a << ‘ ‘ << b << endl;

2003/2004Introdução à Programação53

Indexação fora dos limites (II)

Que sucede? Programa aborta Escreve 3 -1 Escreve -1 3 Escreve 0 -1 ou -1 0 ou 0 3 ou … Escreve 0 0

Sorte!

Pior caso!

2003/2004Introdução à Programação54

Explicação (escreve 3 -1)

m[0]:

0

m: double

[3]

m[1]:

1

m[2]:

2

b:

?

a:

?

Memória

3

-1

2003/2004Introdução à Programação55

Problemas das matrizes (VII)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador Não se podem devolver Passagem sempre por referência (mentirita…) Dimensão ignorada em parâmetros Não há forma de saber dimensão de matriz parâmetro Índices não verificados

2003/2004Introdução à Programação56

Mais problemas…

double valores1[2] = {1.1, 2.2};double valores2[2] = {3.3, 4.4};

if(valores1 != valores2) valores1 = valores2;

Impossível!Impossível!

2003/2004Introdução à Programação57

Problemas das matrizes (VIII)

Inicializadas implicitamente com lixo Inicialização explícita exaustiva… De dimensão fixa De dimensão conhecida pelo compilador Não se podem devolver Passagem sempre por referência (mentirita…) Dimensão ignorada em parâmetros Não há forma de saber dimensão de matriz parâmetro Índices não verificados Atribuições inválidas Comparações inválidas

2003/2004Introdução à Programação58

Matrizes n-dimensionais (I)

double m[2][3] = { {1, 2, 3}, {4, 5, 6}};

Duas linhas e três colunas Matriz de matrizes

Indexável:

m[1][2] = 12.0;

2003/2004Introdução à Programação59

Matrizes n-dimensionais (II)

double (m[2])[3] = {…};

m[0][0]:

1

m[0]: double[3]

m[0][1]:

2

m[0][2]:

3

m[1][0]:

4

m[1]: double[3]

m[1][1]:

5

m[1][2]:

6

m: double[2][3]

2003/2004Introdução à Programação60

Vectores: A solução

#include <vector>

std::vector<double> v(10);

std::vector<double> v(10, 13.0);

std::vector<double> v;

Tipo dos itensNome do vector

Número de itensInicializado com 10 itens de valor zero

Inicializado com 10 itens de valor 13

Inicializado com 0 itens!

Classe genérica

2003/2004Introdução à Programação61

Acedendo à dimensão de vectores

vector<double> v(10, 13.0);cout << v.size() << endl;

instância.operação(argumento, …);

Invocação da operação size().

Instância para a qual a operação é invocada

Nome da operação a invocar

Argumentos a passar à operação

2003/2004Introdução à Programação62

vector<…>::size()

Devolve inteiro sem sinal Tipo não-especificado:

unsigned short int? unsigned int? unsigned long int?

Tipo exacto é sinónimo devector<…>::size_type

2003/2004Introdução à Programação63

Ler 1000 inteiros e escrevê-los por ordem inversa#include <iostream> #include <vector>

using namespace std;

int main() { int const número_de_valores = 1000;

cout << "Introduza " << número_de_valores << " inteiros: "; vector<int> valores(número_de_valores); lêPara(valores);

escreveInvertido(valores); }

2003/2004Introdução à Programação64

lêPara()

/** Lê do teclado valores inteiros que coloca por ordem nos itens do vector passado como argumento. @pre cin.good() cin permite extracção de valores.size() inteiros sucessivos. @post cin.fail() cin já não contém os primeiros valores.size() inteiros que continha inicialmente o vector valores contém-nos pela mesma ordem. */void lêPara(vector<int>& valores) { assert(cin.good());

for(vector<int>::size_type i = 0; i != valores.size(); ++i) cin >> valores[i]; }

2003/2004Introdução à Programação65

escreveInvertida()

/** Escreve no ecrã os elementos do vector passado como argumento começando no último. @pre V. @post cout.fail() cout sofreu inserções dos valores.size() itens do vector valores pela sua ordem inversa. */void escreveInvertido(vector<int> const valores) { for(vector<int>::size_type i = valores.size() - 1; i != -1; --i) cout << valores[i] << endl; }

i é de um tipo sem sinal. Nunca poderá chegar a -1.Guarda sempre verdadeira!

2003/2004Introdução à Programação66

escreveInvertida()

/** Escreve no ecrã os elementos do vector passado como argumento começando no último. @pre V. @post cout.fail() cout sofreu inserções dos valores.size() itens do vector valores pela sua ordem inversa. */void escreveInvertido(vector<int> valores) { for(vector<int>::size_type i = valores.size(); i != 0; --i) cout << valores[i - 1] << endl; }

2003/2004Introdução à Programação67

Leitura com devolução (I)

vector<int> vectorLido(int número_de_valores) { assert(cin.good());

vector<int> valores(número_de_valores); for(vector<int>::size_type i = 0; i != valores.size(); ++i) cin >> valores[i];

return valores; }…int main() { … vector<int> valores = vectorLido(número_de_valores);

escreveInvertido(valores); }

Não é função nem procedimento! Má ideia!

2003/2004Introdução à Programação68

Leitura com devolução (II)

vector<int> vectorLido(int número_de_valores) { assert(cin.good());

vector<int> valores; for(int i = 0; i != número_de_valores; ++i) { int valor; cin >> valor; valores.push_back(valor); }

return valores; }

Não é função nem procedimento! Má ideia!

2003/2004Introdução à Programação69

Vectores por valor?

Vectores podem-se passar por valor Implica cópia do vector Vectores podem ser grandes Passagem por referência não faz cópia Mas permite alterações no parâmetro…

Ideal: vantagens de ambos

2003/2004Introdução à Programação70

Passagem por referência constante

/** Escreve no ecrã os elementos do vector passado como argumento começando no último. @pre V. @post cout.fail() cout sofreu inserções dos valores.size() itens do vector valores pela sua ordem inversa. */void escreveInvertido(vector<int> const& valores) { for(vector<int>::size_type i = valores.size(); i != 0; --i) cout << valores[i - 1] << endl; }

Sinónimo que proíbe alteraçõesInútil para tipos básicos!

2003/2004Introdução à Programação71

Generalização

int main() { cout << "Quantos valores quer que sejam lidos? "; int número_de_valores; cin >> número_de_valores;

cout << "Introduza " << número_de_valores << " inteiros: "; vector<int> valores(número_de_valores); lêPara(valores);

escreveInvertido(valores); }

2003/2004Introdução à Programação72

Redimensionando

vector<int> v(5, 1); v.resize(8); // Novos itens com zero.

v.resize(9, 2); // Novos itens com 2.

v.resize(2);

2003/2004Introdução à Programação73

Vantagens dos vectores

Inicializados implicitamente com zero Inicialização explícita abreviada… Dimensão variável Podem-se devolver Podem-se passar por valor ou por referência Dimensão não é nunca ignorada Pode-se saber dimensão Atribuições válidas Comparações válidas

2003/2004Introdução à Programação74

Problemas dos vectores

Índices não verificados Inicialização exaustiva impossível

2003/2004Introdução à Programação75

Solução recursiva

/** Lê o número de inteiros passado como argumento e escreve-os pela ordem inversa. @pre 0 ≤ numero_de_valores cin.good() cin permite extracção de numero_de_valores inteiros sucessivos. @post cout.fail() cout sofreu inserções dos numero_de_valores inteiros lidos pela sua ordem inversa. */void leEInverteInteiros(int const numero_de_valores){ assert(0 <= numero_de_valores);

if(numero_de_inteiros_a_ler != 0) { int valor; cin >> valor; leEInverteInteiros(numero_de_valores - 1); cout << valor << endl; }}

Onde ficam guardados os valores?

2003/2004Introdução à Programação76

Aula 9: Sumário

Matrizes clássicas do C++: Agregado indexável de instâncias do mesmo tipo Sintaxe: definição e inicialização Particularidades:

• dimensão constante• proibidas atribuições, comparações e devoluções• passagens sempre por referência• indexações fora dos limites não verificadas

Indexação fora dos limites: sintomatologia Vectores:

Vantagens face a matrizes Operações da classe genérica vector

top related