Este é mais um serviço de utilidade pública que presto de bom grado, desta feita para o pessoal da programação de computadores, em particular alunos e (espantem-se) professores: arrays e vectores não são a mesma coisa!
Um array é, na sua essência, apenas um bloco de memória suficientemente grande para armazenar um número concreto de elementos. Se estivermos a programar um sistema em que um caractere ASCII ocupa exactamente 1 byte, então um array de 10 chars vai ocupar 10 bytes. Se forem longs e cada long ocupar 4 bytes, um array de 10 longs corresponderá a um bloco de memória de 40 bytes.
Outra característica dos arrays é que se criamos um array de 10 elementos, sejam eles ints, chars, ou outra coisa qualquer, o array vai manter aquele tamanho até ser destruído. De notar que isto não se aplica inteiramente a algumas linguagens, particularmente linguagens de “scripting” como PHP, já que o seu conceito de array é um pouco distorcido e é mais um vector ou um dicionário do que um array.
Geralmente um array não é mais do que um apontador para o início do bloco de memória que representa. Quando acedemos a um elemento do array através de parêntesis rectos (o operador []), o que estamos a fazer é usar o apontador do array como endereço base e dizer-lhe para “avançar” X bytes na memória.
É mais fácil do que parece. Um exemplo ajuda: imaginemos o array int[] myarray = new int[10], ocupando cada int exactamente 2 bytes. Este array vai apontar para um bloco de memória de 20 bytes. Supondo que esse bloco de memória começa no endereço 0x0050, o primeiro elemento do array ocupará a memória de 0x0050 a 0x0051 (2 bytes), o segundo elemento estará no espaço de memória de 0x0052 a 0x0053, o terceiro em 0x0054 a 0x0055, e por aí fora. Se em vez de int usarmos long, os quais ocupam 4 bytes cada, então o primeiro elemento ocuparia a memória de 0x0050 a 0x0053, o segundo de 0x0054 a 0x0057, o terceiro de 0x0058 a 0x0061, etc.
Ao acedermos a myarray[2], o que estamos a fazer é adicionar ao endereço base do array o número de bytes ocupado pelo tipo de elementos, multiplicado pelo número de elementos que queremos passar à frente. Neste caso o endereço base é 0x0050 e cada int ocupa dois bytes. Se queremos aceder ao elemento de índice 2, então temos que “saltar” dois elementos (índice a começar em 0, portanto é o terceiro elemento). Se cada int ocupa dois bytes, então queremos saltar 4 bytes no total e começamos a ler no endereço 0x0054. Se fossem longs quereríamos saltar 8 bytes (4 por cada um dos dois elementos a saltar) e começávamos a ler no endereço 0x0058.
De forma mais genérica, se queremos aceder ao elemento i de um array de elementos do tipo T, então o endereço de memória a que queremos aceder é o endereço base + (i * sizeof(T)).
Voltando ao array de ints, o cálculo é este: 0x0050 + (2 * sizeof(int)) = 0x0054. Como é um int e um int ocupa 2 bytes (sizeof(int) == 2), é só ler os bytes 0x0054 e 0x0055 e temos o nosso elemento.
E para o array de longs: 0x0050 + (2 * sizeof(long)) = 0x0058. Como é um long e um long ocupa 4 bytes (sizeof(long) == 4), é só ler os bytes 0x0058 e 0x0062 e temos o nosso elemento.
E o que é que acontece se tentarmos aceder a myarray[10] (11º elemento) ou myarray[11] (12º elemento)? Estaremos a aceder a elementos que não pertencem ao array, pois as contas anteriores levar-nos-iam para endereços de memória que já estariam fora do mesmo. Se só quisermos ler, vamos acabar com valores imprevisíveis, pois não sabemos o que é que está fora do array. Se escrevermos para lá alguma coisa, podemos estoirar com o nosso programa por estarmos a mexer onde não devemos.
Isto tudo para explicar que esta é uma das grandes diferenças entre um vector e um array - um vector bem implementado à partida não deverá permitir o acesso a secções de memória que não lhe pertencem.
Um vector é uma estrutura de dados um pouco mais complexa que um array e, apesar de geralmente funcionar praticamente como um, permitindo o acesso indexado aos seus elementos, o que acontece “lá dentro” é muito diferente. Um vector é um array “dinâmico”, que cresce conforme necessário. Para o pessoal da geração Java, um exemplo de um array dinâmico são as ArrayLists. Para o pessoal do PHP, os arrays nativos de PHP já são arrays dinâmicos (tecnicamente são dicionários, mas isso é outra história). E haverá muitos outros exemplos de arrays dinâmicos largamente utilizados mas a ideia crítica aqui é que os arrays no seu conceito mais tradicional não são dinâmicos.
Um vector regra geral tem arrays “lá dentro” mas não lhes acedemos directamente, ao contrário do que acontece com arrays simples. Um vector fornece alguma forma de acesso para consulta e manipulação aos dados que contém mas nós, enquanto utilizadores do vector, não precisamos de nos preocupar (até certo ponto) com o tamanho do vector (ao contrário do que acontece com arrays), pois este deve poder crescer à medida que for ficando cheio. Isto é geralmente implementado alocando outro array e guardando os novos elementos nesse novo array. Claro que isto significa que o vector tem de saber onde é que os elementos estão guardados, para poder encontrar os nossos dados quando já tiver crescido várias vezes.
Para além disto, um vector oferece normalmente outras funcionalidades, como iteradores, possibilidade de saber se contém um determinado elemento, possibilidade de crescer ou decrescer por ordem do utilizador, entre muitas outras coisas que ficam ao critério de quem o implementa.
Como vêem, um vector não é a mesma coisa que um array, portanto por favor, professores (especialmente os professores) e alunos, parem de usar os dois termos como se fossem sinónimos. Já basta as universidades andarem a desleixar-se no ensino da programação, não são precisas mais ideias erradas na cabeça de quem está a aprender estas coisas.
Raúl Santos