Programar em C/Índice/Vetores
Origem: Wikilivros, livros abertos por um mundo aberto.
| Foi proposta a fusão deste módulo com: Programar em C/Vetores (discuta). |
Tabela de conteúdo |
[editar] Declarando array
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 da mesma tipologia
- Reparem que o valor do size declarator é um número. É 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?
aqui vai uma tentativa
#include <iostream>
using namespace std;
int main ()
{
int numTests;
cout << "Enter the number of test scores:";
cin >> numTests;
int testScore[numTests];
system (“pause”);
return 0;
}
Isto vai dar um erro de compilação, porque o array está á 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.
[editar] 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.
[editar] Declarar constantes
É exactamente como declarar uma variável com duas diferenças:
- A declaração começa com a palavra const. Isto vai dizer ao compilador que é uma constante e não uma variável
- 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]
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.
[editar] 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 valores 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
[editar] 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 programadores, é 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
[editar] 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];
[editar] inicializando
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 elementos são seguidos e do mesmo tipo
| a[0][0] | a[0][1] | a[0][2] | a[1][0] | a[1][1] | a[1][2] | |
| 1 | 2 | 3 | 4 | 5 | 6 |
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 espaç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.
[editar] 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
[editar] 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;
system (“pause”);
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;
}
system (“pause”);
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;
}
system (“pause”);
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
system ("pause");
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.
[editar] 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;
}
system ("pause");
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 MAX = 3;
int main ()
{
int testScore[MAX];
assignValues(testScore, MAX);
displayValues(testScore, MAX);
system ("pause");
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;
}
}
[editar] 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
system (“pause”);
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”;
}
system (“pause”);
return 0;
}
void doubleThem(int a[], int size)
{
int i;
for (i = 0; i < size; i++)
{
a[i] = 2 * a[i];
}
}