Programar em C++/Vetores

Façamos uma pequena revisão de conceitos:
Vetores e matrizes são variáveis compostas homogêneas,
ou seja, são agrupamentos de dados que individualmente
ocupam o mesmo tamanho na memória
e são referenciados pelo mesmo nome, geralmente
são individualizadas usando-se índices.
Vetores distinguem-se das matrizes apenas pela característica
de ter dimensão (1 x n) ou (n x 1), essencialmente
vetores são matrizes linha ou matrizes
coluna.
Em linguagem “C” vetores e matrizes são usados abundantemente
para compor estruturas de dados necessárias
para composição de diversos recursos. Esta usa, mais explicitamente,
vetores de caracteres para definir cadeias de
texto, o que é conhecido como o mais trivial uso de vetores.
Além deste recurso, o “C” também define meio de
criação de matrizes tipo (n x m), provendo, desta forma
os recursos necessários para criação destes conjuntos de
dados.
A linguagem “C++" suporta os mesmos recursos e permite
a criação de matrizes de objetos. Uma vez que um
objeto é essencialmente um tipo de dado criado pelo programador,
todas as características básicas legadas aos “tipos”
em geral são observados nos tipos criados (classes de
objetos).
1 Vetores
Os vetores em C++ seguem a mesma notação da linguagem “C”, via de regra declara-se o tipo seguido de um asterisco.
Para acessar o valor apontado pela variável usa-se um asterisco de forma semelhante, como pode ser visto no trecho de código abaixo:
int *x;
int a = 3; 
x = &a;
cout <<" O valor do conteúdo da posição 0x"; // O valor da posição 0x23A0209112
cout << hex << x << “de memória é " << *x << endl; // de memória é 3
2 Matrizes
Podemos imaginar que uma matriz é um conjunto de vetores que ocupam uma determinada área de memória referenciada por um nome comum. Matrizes de tipos primitivos são conseguidas através de associações do operador [ ], como por exemplo:

char A[32][16];
int B[12][26][10];

Definindo nossas classes de objetos poderemos declarar matrizes de objetos:
class Record 
{ int D; float X,Y; char desc[12];
 public:
Record(); void addFData(float A, float B); float getFDataX();
float getFDataY(); ... ... ... }; void function() {
Record A[32][16]; ... ... ...

Ou seja, podemos adotar a mesma sintaxe para criar matrizes de objetos. Este procedimento pode ser usado com o cuidado de se avaliar antes a quantidade de memória disponível para que a matriz não ultrapasse esse limite físico, muitas vezes delimitada pelo hardware ou pelo sistema
operacional. Lembremos que, um objeto precisa do espaço equivalente a soma de suas variáveis internas para ser alocado na memória.

3 Declarando arranjo

Os arrays permitem fazer o seguinte:
int a1, a2, a3,….a100;
é equivalente a ter
int a[100];
Ou seja permite declarar muitas variáveis de uma forma bem simples, poupa escrita e é bastante compreensível.
O número que está dentro de brackets [] é o size declarator.
Ele é que vai permitir ao computador dizer quantas variáveis a serem geradas e logo quanta memória deverá ser reservada. A memória reservada para as variáveis vão ser todas seguidas, um int a seguir ao outro
Há uma forma para não dizer o valor deste size declarator, mas isso apenas acontece antes da compilação, ou seja o compilador é que vai fazer esse preenchimento por nós, visualizando o nosso código e contanto os membros que colocámos. Isto é um automatismo dos compiladores recentes. chama-se a isto iniciação implícita que vamos ver nesta secção.
As variáveis geradas pelos arrays vão ser todos do mesmo tipo.
Reparem que o valor do size declarator é um número.

CARACTER ARRAY

É literal, ele não vai mudar quando o programa estiver a correr. Por isso quando não soubermos o número de elementos o que fazemos?
Veja uma tentativa:
#include <iostream>
 using namespace std; 
int main () {
int numTests
 cout << “Enter the number of test scores:";
cin >> numTests; 
int testScore[numTests]; 
return 0; }
Isto vai dar um erro de compilação, porque o array está a espera de uma constante e não uma variável. Há uma maneira de contornar isto que é através da memória dinâmica que vamos dar mais tarde, num capitulo próprio, pois isto vai envolver muitos conceitos.

4 Constantes

Reparem que há uma diferença entre literais e constantes, apesar de em ambos os casos o valor não é alterado durante a execução do programa, a constant é um nome
que representa o valor, o literal é o valor.

5 Declarar constantes

É exatamente como declarar uma variável com duas diferenças:
1. A declaração começa com a palavra const. Isto vai dizer ao compilador que é uma constante e não uma variável
2. Teremos de atribuir logo o valor na declaração, ou seja, é fazer a iniciação
Exemplo:
const int numTests = 3;
Portanto se tentarmos colocar um outro valor ao numTest, isso vai dar um erro de compilação
Array index
a[100] é composto por a[0], a[1],… a[99] ( De a[0],
a[1],… a[99] existe 100 posições)
Pergunta:
Porque é que o índex começa em zero e não um?
Ou seja temos as 100 posições que pedimos mas o índex começa no zero e não no 1. A razão disto tem a ver com offset – que refere ao valor adicionado para o endereço base para produzir a segunda address. Bem não entendi bem! Eu explico de novo: O endereço (address) do primeiro elemento do array, é o mesmo do que o endereço base do próprio array. ah espera aí, o que estão
a dizer é que o endereço do array é igual ao do primeiro elemento do array. Assim o valor que teria de ser adicionado, ao endereço base do array, para conseguirmos o endereço do primeiro elemento seria zero. Agora sim, percebi!
Erro:
Um erro comum é esquecer que o index começa no zero, e portanto quando se querem referir ao último elemento, esquecem-se que têm de subtrair uma unidade. O que advém desse esquecimento é que podem estar a alterar memória pertencente a uma variável, instrução,..de um outro programa. – Ou seja vai existir violação de dados.
Se o array for declarado globalmente em vez de ser localmente, então cada elemento é inicializado ao valor defaut que é zero.

6 Iniciação

Iniciação, se bem se recordam é atribuir um valor a uma
variável ao mesmo tempo que declaramos a variável. Podemos
fazer a iniciação de um array de 2 maneiras:
1) explicit array sizing
int testScore[3] = { 74, 87, 91 }; float milesPerGallon[4]
= { 44.4, 22.3, 11.6, 33.3}; char grades[5] = {'A', 'B', 'C',
'D', 'F' }; string days[7] = {"Sunday”, “Monday”, “Tuesday”,
“Wednesday”,"Thursday”, “Friday”, “Saturday"};
Pergunta: O que é que acontece se dermos mais valores
de atribuição do que elementos do array?
int a[3] = { 74, 87, 91, 45 };
Isto vai dar um erro de compilação “too many initializers”
Pergunta:
O que é que acontece se tivermos menos va-
lores do que os elementos?
int a[3] = { 74 };
Não acontece nada simplesmente não temos valores para
a[1] e a[2]. Porém em alguns compiladores os elementos
não inicializados ficam com os valores defaut, que no
caso dos ints é 0 no caso dos floats é 0.0 e nos caracteres
é o caractere nulo ("\0”). No entanto se não inicializarmos
um dos elementos, os restantes elementos terão de
ser não inicializados pois caso contrário teremos um erro
de compilação
2) implicit array sizing
int testScore[ ] = { 74, 87, 91 }; float milesPerGallon[ ]
= { 44.4, 22.3, 11.6, 33.3}; char grades[ ] = {'A', 'B', 'C',
'D', 'F' };
Aqui o compilador faz o trabalho por nós, conta os elementos
e preenche o número de elementos

7 Caracter array

char name[ ] = {'J', 'e', 'f', 'f', '\0' }; char name[ ] = “Jeff";
Ambas as inicializações são permitidas. Porém tomar
atenção á ultima iniciação! Quando colocámos as aspas
duplas o compilador acrescenta o "\0” na array que cria!
Não tem []!! Esta até costuma ser a preferida pelos pro-
gramadores, é ao estilo de strings (Na verdade as strings
são arrays de char mas vamos falar disso num capitulo
próprio)
O char "\0” é o escape sequence para caracterer null. Este
escape sequence sinaliza ao cout o fim do character array.
É o último elemento do array preenchido! Se não tivéssemos
este carácter apareceriam estranhos caracteres a
seguir ao “jeff”, chamados “caracteres-lixo”. (porquê?)
Isto não significa que o último elemento deva ser sempre
o null carácter

8 Arrays de várias dimensões

Podemos ter duas dimensões
tipo_da_variável nome_da_variável [altura][largura];
como também poderíamos ter infinitas
tipo_da_variável nome_da_variável [tam1][tam2] ...
[tamN];

9 Iniciando

float vect [6] = { 1.3, 4.5, 2.7, 4.1, 0.0, 100.1 }; int matrx
[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; char str
[10] = { 'J', 'o', 'a', 'o', '\0' }; char str [10] = “Joao"; char
str_vect [3][10] = { “Joao”, “Maria”, “Jose” };
Peguemos no exemplo:
int a [2][3]={1,2,3,4,5,6,}
Na memória teríamos as coisas assim. ou seja os elemen-
tos são seguidos e do mesmo tipo
Portanto ter int a [2][3] é equivalente a ter int a [6] o nome
que se dá é que é diferente.
Pergunta: será pedido espaço par 6 ints ou antes um es-
paço com o tamanho de 6 ints? Como nós sabemos que
os arrays os elementos têm endereços de memoria consecutivos,
por isso, não podem ser pedidos 6 ints, pois se
fosse esse o caso, poderia acontecer que eles não ficassem
juntos.
10 Const Constant arrays
const int daysInMonth [] = { 31, 28, 31, 30, 31, 30, 31,
31, 30, 31, 30, 31 };
Recordar que temos de inicializar quando queremos fazer
uma constante array
11 Atribuir valores ao array
#include <iostream> using namespace std; int main () {
int testScore[3]; cout << “Enter test score #1: "; cin >>
testScore[0]; cout << “Enter test score #2: "; cin >> testScore[1];
cout << “Enter test score #3: "; cin >> testScore[2];
cout << “Test score #1: " << testScore[0] <<
endl; cout << “Test score #2: " << testScore[1] << endl;
cout << “Test score #3: " << testScore[2] << endl; return
0; }
Podemos atribuir o valor 1 a 1, mas para poupar escrita de
programação é melhor utilizar as funções anteriormente
revistas como o for
#include <iostream> using namespace std; int main () {
int testScore[3]; for (int i = 0; i < 3; i++) { cout << “Enter
test score #" << i + 1 << ": "; cin >> testScore[i]; } for (i
= 0; i < 3; i++) { cout << “Test score #" << i + 1 << ": "
<< testScore[i] << endl; } return 0; }
Ou melhor ainda podemos usar uma constante, para tornar
o nosso código mais abstracto.
#include <iostream> using namespace std; const int
MAX = 3; int main () { int testScore[MAX]; for (int i
= 0; i < MAX; i++) { cout << “Enter test score #" << i +
1 << ": "; cin >> testScore[i]; } for (i = 0; i < MAX; i++)
{ cout << “Test score #" << i + 1 << ": " << testScore[i]
<< endl; } return 0; }
Lembram-se da história de termos o endereço do array
igual ao endereço do 1º elemento do array?
#include <iostream> using namespace std; const int
MAX = 3; int main () { int testScore[3] = { 74, 87, 91 };
cout << testScore[0] <<"\n"; cout << testScore <<"\n";
//array base e não um elemento particular do array return
0; }
Pois bem vemos que quando mandamos imprimir o array,
ele dá um endereço. Pois o valor do nome do array é o
endereço do array.
12 Arrays como statements de funções
Pegando no programa
#include <iostream> using namespace std; const int
MAX = 3; int main () { int testScore[MAX]; for (int i
= 0; i < MAX; i++) { cout << “Enter test score #" << i +
1 << ": "; cin >> testScore[i]; } for (i = 0; i < MAX; i++)
{ cout << “Test score #" << i + 1 << ": " << testScore[i]
<< endl; } return 0; }
Vamos torná-lo mais modular, escrevendo uma função
para atribuir valores ao array e outa função para mostrar
os valores do array
#include <iostream> using namespace std; void assignValues(int[],
int); void displayValues(int[], int); const int
3
4 13 ARRAYS COMO ARGUMENTOS DE FUNÇÕES
MAX = 3; int main () { int testScore[MAX]; assignValues(testScore,
MAX); displayValues(testScore, MAX);
return 0; } void assignValues(int tests[], int num) { for
(int i = 0; i < num; i++) { cout << “Enter test score #" <<
i + 1 << ": "; cin >> tests[i]; } } void displayValues(int
scores[], int elems) { for (int i = 0; i < elems; i++) { cout
<< “Test score #" << i + 1 << ": "<< scores[i] << endl; }
}
13 Arrays como argumentos de
funções
// arrays as parameters #include <iostream> using namespace
std; void printarray (int array[], int length) /*função
com 2 argumentos,um deles é um array */ { for (int n=0;
n<length; n++) cout << array[n] << " "; cout << "\n"; }
int main () { int a[] = {5, 10, 15}; printarray (a,3); //passo
array como argumento return 0; }
Este exemplo por acaso está muito curioso
Pergunta: mas agora deveríamos perguntar se neste caso
tínhamos uma passagem por valor ou referência.
Quando um array é passado para uma função, a função
recebe não a cópia do array mas invés disso o endereço,
address do primeiro elemento do array, que é igual ao
valor do array (base).
Assim todas as modificações que se efectuarem na função
que foi chamada irão repercutir-se no array passado.
Vamos confirmar:
#include <iostream> using namespace std; void
doubleThem(int a[], int size); int main() { int
a; int myInts[10] = {1,2,3,4,5,6,7,8,9,10}; doubleThem(myInts,
10); //passei o array base for (a=0;
a<10; a++) { cout << myInts[a] <<”\t”; } return 0; }
void doubleThem(int a[], int size) { int i; for (i = 0; i <
size; i++) { a[i] = 2 * a[i]; } }

Comentários

Mensagens populares deste blogue

Introdução a Linguagem Java

XIII Mostra de Ciência Tecnologia e Inovação em Moçambique