Entendendo Arrays
Para entender o array de forma precisa, é interessante compreender um pouco sobre memória, tipos de dados e endereçamento, mesmo que de forma superficial. Digo isso porque o array é uma das formas mais básicas de dados estruturados. Podemos considerar o array uma base para vários tipos de estruturas de dados mais complexas, como por exemplo Vetor Dinâmico, Fila circular, pilha e por aí vai. Então eu resolvi criar esse artigo para explicar o array de uma forma que, pelo menos para mim, ajudou para que eu compreendesse de vez, e não esquecesse mais. Espero que também ajude quem está aprendendo agora.
Array por baixo do capô
Vamos resumir o array da forma que mais lemos e escutamos por aí só para ter a base do raciocínio.
O array é uma sequência de elementos, todos do mesmo tipo armazenados de forma contígua na memória. Cada elemento do array é acessível por um índice, que geralmente começa em 0. Cada índice em um array é uma referência (ou ponteiro) para uma posição específica na memória onde o valor correspondente está armazenado. O array tem um tamanho fixo, que não pode ser alterado.
Imagem com fundo claro
Maravilha! Agora você sabe que o array é uma sequência de elementos do mesmo tipo, que você pode acessar esses elementos pelo índice, cada índice faz uma referência (aponta) para o endereço de memória onde o elemento (a informação) está guardada e que o tamanho é fixo.
Mas, por que somente elementos do mesmo tipo? E por que o tamanho de um array não pode ser dinâmico? (obs. estamos falando de arrays homogêneos aqui, e não as listas de python e JavaScript que aceitam tipos diferentes, esses são Heterogêneos).
Vamos entender isso:
Tipos de dados: os dados são uma representação da informação. Cada tipo de dado serve para representar uma informação específica e ocupa uma quantidade de memória necessária para isso.
Por exemplo:
Inteiros e números de ponto flutuante possuem tamanhos diferentes porque representam informações distintas, isso exige alocações de memória específicas para cada tipo.
Um inteiro em Java, por exemplo, ocupa um espaço de 32 bits para ser representado, pode conter valores de -2.147.483.648 a 2.147.483.647.
Já um double ocupa um espaço de 64 bits para ser representado, pode conter valores de ponto flutuante de IEEE 754 ±4,94065645841246544e-324 a 81,79769313486231570e+308.
A memória é organizada em células, elas contém um endereço único que serve para localizar os dados armazenados naquele espaço específico
Por isso quando criamos um array precisamos informar qual será o tipo de dado e a quantidade a ser armazenada. Isso permite que o sistema aloque espaço fixo suficiente na memória para guardar esses dados. O sistema calcula esse espaço multiplicando o tamanho do tipo de dado pela quantidade de elementos. Por exemplo, um array de inteiros com 10 elementos ocupará um espaço de memória ao tamanho de um inteiro multiplicado por 10.
No exemplo com Java seria 32 bits (4 bytes) x 10 = 40 bytes. Essa alocação fixa torna o uso eficiente, pois o sistema sabe exatamente quanto espaço precisa para armazenar os dados.
Imagem com fundo claro
Acesso direto
Para ter a referência de cada valor armazenado nesse espaço contíguo de memória, cada índice do array aponta para cada endereço naquela memória alocada, permitindo acessar cada elemento diretamente, sem ter que percorrer cada endereço um por um. Isso é conhecido como acesso direto.
Para ter o acesso direto é preciso realizar o cálculo de endereço, que só é possível de ser realizado tendo a informação do tipo de dado e quantidade (que é passada ao criar o array).
A partir da fórmula: valor do endereço n = endereço base + ( n x tamanho do tipo de dado) podemos encontrar qualquer valor no array.
onde:
Endereço base é o endereço de memória do primeiro elemento do array (índice 0).
n é o índice do elemento que queremos acessar tamanho do tipo de dado é a quantidade de bytes que cada elemento ocupa na memória.
tamanho do tipo de dado é a quantidade de bytes que cada elemento ocupa na memória.
Para um array de inteiros em Java:
Onde o endereço base seja 1000 (em bytes).
Cada int ocupa 4 bytes.
Se quisermos o endereço do elemento no índice 3, a fórmula seria: Endereço do elemento 3 = 1000 +(3×4) =1 000+12 = 1012.
Ou seja, o valor do elemento no índice 3 está no endereço de memória 1012.
Arrays são ideais quando se precisa de uma estrutura de dados compacta, de tamanho fixo, acesso rápido e previsível. São muito úteis para armazenar dados quando o tamanho e tipo dos elementos são conhecidos previamente. Também são base para alguma outras estruturas de dados mais elaboradas, como vetores dinâmicos, filas e listas ligadas.
Desvantagens
Uma das limitações signiificativas dos arrays é seu tamanho fixo. Isso significa que, uma vez declarado não pode aumentar ou diminuir seu tamanho, o que torna essa estrutura inadequada para situações em que a quantidade de dados é variável ou desconhecida.
Em um array, inserir ou remover elementos especialmente em posições intermediárias, é uma operação complexa. Para inserir um elemento no meio de um array, é necessário deslocar todos os elementos posteriores para abrir espaço, para remover, fechar a lacuna deixada.
Para finalizar
Ao entender as limitações e pontos fortes dos arrays, conseguimos ver que cada estrutura tem seu lugar no design de software. A estrutura certa para cada situação e o que torna o código mais eficiente e fácil de manter.
Entender esses conceitos de alocação de memória, endereçamento e tipos de dados nos ajuda a compreender como um array funciona, porque devemos declarar seus tipos e quantidades de elementos na sua criação, o que é o acesso direto e porque é possível realizá-lo. Motivos que o torna eficiente em acesso de elementos porém ineficiente em flexibilidade e inserções e remoções no meio do array.
Espero que este artigo tenha ajudado a entender melhor como funciona o array, e com certeza correções e melhores esclarecimentos são muito bem vindos.