
Do básico ao intermediário: Array (II)
Introdução
O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como uma aplicação final, onde o objetivo não seja o estudo dos conceitos aqui mostrados.
No artigo anterior Do básico ao intermediário: Array (I), começamos a falar de um dos temas mais complicados e difíceis de dominar que existe na programação. Sei que muitos podem dizer que aquilo é algo simples. E que não faz sentido eu dizer que é tão complicado assim. Porém, conforme formos avançando, você irá entender por que eu digo que este tema é de fato complicado e difícil de dominar. Visto que ele é a base para todo o resto.
Uma vez que eu tiver explicado e mostrado, como este tipo de coisa de fato pode ser utilizada. Você, meu caro leitor, que conseguir assimilar bem o que será demonstrado. Irá com toda a certeza, entender o porquê de existir outras coisas em uma linguagem de programação. Já que todo o resto, será muito mais simples de dominar e compreender.
A maior dificuldade aqui, é na verdade apresentar as coisas de maneira que não entremos em outros temas, ainda não vistos. Estou tentando mostrar, por que algumas coisas foram criadas. Sem de fato as mostrar ainda. Isto por que, entender o conceito por trás de tais ferramentas, é muito mais importante do que entender a ferramenta em si. E como grande parte dos programadores, muitas das vezes ignoram o conceito, e se apega a ferramenta. Acabam ficando de mãos atadas, em certos momentos. Isto por que, não é a ferramenta que resolve o problema. Mas sim, o conceito. É como um martelo. Ele pode servir para pregar coisas. Porém também serve para demolir coisas. Apesar de existir uma ferramenta melhor, que seria uma marreta.
Muito bem, antes de começarmos, existe um pré-requisito que será necessário para compreender este artigo. O mesmo é conhecer e entender o que seria uma variável e o que seria uma constante.
Array tipo ROM
Existem basicamente duas formas de se declarar um array. Uma é declarando um array estático e a outra é declarando-o como um array dinâmico. Apesar de que na prática entender cada um é relativamente simples. Existem algumas pequenas nuances que dificultam, ou impossibilita que tenhamos um entendimento correto do que seria um array dinâmico e o que seria um array estático. Isto quando falamos de outras linguagens. Especialmente C e C++. No entanto, mesmo aqui no MQL5, em alguns momentos você pode ficar meio que na dúvida. Isto por que, a diferença básica e essencial que existe entre um array estático e um dinâmico, é a possibilidade de ele poder mudar de tamanho, durante a execução do código.
Pensando desta maneira parece simples, classificar um array como sendo dinâmico ou estático. Porém, vale lembrar que uma string é um array. Só que um array especial. O que a torna complicado de ser classificada como estática ou dinâmica. No entanto, vamos ignorar este fato. E não mexer diretamente com o tipo string. Isto para evitar confusão e impedir que venhamos a ter um correto entendimento sobre este tema.
Basicamente, e isto sem que nenhuma discussão venha a surgir. Seja em qualquer linguagem de programação, que você por ventura vier a estudar no futuro. Um array do tipo constante, é sempre um array estático. Não importa a linguagem que você o utilize. Ele SEMPRE será do tipo estático.
Bem, mas por que podemos afirmar que um array constante é sempre do tipo estático? O motivo para isto é que um array constante, e você precisa pensar nele desta forma, é na verdade uma memória ROM. Neste ponto, talvez a coisa não faça muito sentido. Isto por que, nossa aplicação sempre será colocada para ser executada em uma região da memória RAM. Como então podemos imaginar uma memória ROM, na qual apenas poderemos ler dados, dentro de uma memória RAM, que por sua vez, nos permite ler e escrever informações, em qualquer ponto da mesma. Isto definitivamente não faz sentido.
Justamente por conta disto, é necessário que você entenda o que seria constante e variáveis, meu caro leitor. Mas sim, pelo ponto de vista, de nossa aplicação, podemos ter uma memória ROM, sendo utilizada, sem que isto comprometa de fato a integridade e usabilidade de nossa aplicação. Na verdade, usar arrays constantes, a fim de criar uma pequena ROM em uma aplicação, é algo relativamente comum. Isto em códigos mais complexos, ou que necessitem de valores muito específicos, e que não venham a mudar de forma alguma.
Pense nas mensagens que são usadas, para reportar algo. Você as pode colocar todas juntas e as traduzir para diferentes idiomas. No momento em que a aplicação for ser carregada, seria verificado o idioma a ser usado nas mensagens e a memória ROM seria construída. Permitindo que a aplicação fosse utilizada, por diferentes usuários, que utilizam diferentes idiomas. Esta seria uma aplicação para um array que estaria em uma ROM. Porém, se você vier a utilizar arquivos, com as traduções e necessitar carregar o arquivo correto. Não mais teríamos um array do tipo ROM. Ou puramente estático. Apesar de ele continuar podendo ser classificado desta maneira.
Para tornar isto mais simples de entender. Já que este conceito é importante, para você saber como e quando poderá utilizar as chamadas da biblioteca padrão, a fim de controlar arrays. Vamos ver um exemplo simples. Onde teremos este tipo de coisa sendo vista na prática.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. const char Rom_01[] = {72, 101, 108, 111, 33}; 07. const char Rom_02[8] = {'H', 'e', 'l', 'o', '!'}; 08. 09. PrintFormat("%c%c%c%c%c%c", Rom_01[0], Rom_01[1], Rom_02[2], Rom_01[2], Rom_02[3], Rom_01[4]); 10. } 11. //+------------------------------------------------------------------+
Código 01
Quando este código 01 é executado, o resultado é mostrado logo abaixo.
Imagem 01
Algo bastante simples de entender. No entanto, o que nos interessa de fato aqui, são as linhas seis e sete. Em ambos os casos temos duas ROMs sendo criadas aqui, e ambas com o mesmo conteúdo, aparente. Porém com tamanhos totalmente diferentes. Mas espere um pouco aí. Como assim? Não entendi. Olhando o código, vejo que ambas têm cinco elementos. E que todos os elementos mostrados ali são iguais. Apenas declarados de maneira diferente. Mas não consigo entender por que apesar disto, estas duas ROMs são diferentes. Isto para mim não faz sentido.
É verdade, meu caro leitor, que ambas têm os mesmos elementos, sendo declarados. Porém de um modo diferente. Mas o que as torna diferente é justamente a declaração das mesmas. Agora preste atenção para entender uma coisa importante aqui.
A ROM_01, que está sendo declarada na linha seis, conta com cinco elementos. Normalmente em um código, onde criamos um array estático. Teremos este tipo de declaração sendo feita. Ou seja, não existe um valor dentro dos colchetes. Mas, e está é a parte que muita gente fica confusa. Não declarar um valor entre os colchetes, no caso de um array constante. É algo perfeitamente normal. E até mesmo bastante usual. Isto por que, você fica livre para adicionar, DURANTE A IMPLEMENTAÇÃO, mais ou menos valores dentro do array. Os valores que forem colocados ali, ficarão completamente travados, não podendo ser modificados depois. Com isto, o tamanho do array, fica sendo o número de elementos presentes no mesmo.
Agora com relação a ROM_02, a coisa é um pouco diferente. Neste caso, temos declarados cinco elementos. No entanto, devido ao fato de estarmos dizendo que o array tem oito elementos. Três destes elementos são desconhecidos. Você deve tomar cuidado ao utilizar estes elementos desconhecidos. Isto por que, pode ser que eles tenham um dado valor. Mas também pode ser que eles tenham um valor completamente aleatório. Já que isto dependerá de como o compilador irá criar o array. Lembrando que estamos trabalhando com arrays do tipo constante.
De qualquer maneira, em ambos os casos teremos um array do tipo estático. Ou seja, a quantidade de elementos, NÃO IRÁ MUDAR, isto durante todo o tempo de vida do array. Sendo que em um caso teremos sempre cinco elementos e no outro sempre oito elementos. Lembrando que o primeiro elemento tem índice igual a zero. Ou seja, a contagem sempre inicia em zero.
Ok. Sabemos quantos elementos existem em cada um dos arrays. Mas o que acontece se tentarmos ler o elemento de índice igual a cinco? Lembrando que a contagem inicia em zero. Bem, neste caso podemos fazer um pequeno teste para que você possa verificar isto. Para tal vamos mudar uma coisa no código, de modo que ele fique como mostrado logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. const char Rom_01[] = {72, 101, 108, 111, 33}; 07. const char Rom_02[8] = {'H', 'e', 'l', 'o', '!'}; 08. 09. const uchar pos = 6; 10. 11. PrintFormat("%c%c%c%c%c%c", Rom_01[0], Rom_01[1], Rom_02[2], Rom_01[2], Rom_02[3], Rom_01[4]); 12. 13. PrintFormat("Contents of position %d of the ROM_02 array: %d", pos, Rom_02[pos - 1]); 14. PrintFormat("Contents of position %d of the ROM_01 array: %d", pos, Rom_01[pos - 1]); 15. } 16. //+------------------------------------------------------------------+
Código 02
Note que agora temos na linha nove deste código 02, uma constante para indicar qual elementos estamos querendo acessar. No caso queremos o sexto elemento. Mas ele está na posição cinco. Você pode pensar, bem, como estamos procurando o elemento na posição cinco. E temos cinco elementos sendo declarados. E queremos imprimir o valor decimal deste elemento, iremos nas linhas 13 e 14 imprimir o mesmo valor, ou seja, 33. De fato, esta é a forma mais natural de pensar. No entanto, ela está errada. Isto por que, a contagem se inicia em zero. Então o quinto elemento que está sendo declarado. É na verdade o elemento, cujo index é o quatro. Assim quando formos tentar acessar o index cinco, algo vai acontecer no código. E o resultado é o que você pode observar logo abaixo.
Imagem 02
Note que aqui temos duas coisas estranhas acontecendo. A primeira é o fato de que a linha 13, foi executada e o resultado mostrado é um zero. Ou seja, o array declarado na linha sete, contém valores ocultos. Mas a parte importante está justamente na mensagem de erro, vista nesta imagem 02. Ela está nos dizendo, que na linha 14 do código 02 existe uma tentativa de acessar algo fora do array. Como o array a ser utilizado nesta linha 14, é justamente o array declarado na linha seis. Você pode ficar meio que sem entender por que da falha está sendo gerada. Isto por conta justamente do fato de que você está tentando acessar o elemento que está na quinta posição. E como o array tem cinco elementos, deveria ser possível fazer isto. Mas novamente, a contagem se inicia a partir do zero.
E para confirmar isto. Vamos fazer uma mudança. E esta é na linha nove deste código 02. Ao mudarmos o valor seis, visto ali, para o valor cinco. Como mostrado na linha de código abaixo, as coisas irão mudar.
const uchar pos = 5;
Ao compilar e executar novamente o código 02, usando esta linha mostrada acima, o resultado no terminal é visto logo na sequência.
Imagem 03
Percebeu como agora o código consegui de fato mostrar o conteúdo correto? Com isto, acredito que você, conseguirá compreender como devemos acessar arrays. E como aquela pequena diferença na declaração dos array, pode nos levar a um tipo de resultado completamente distinto.
Muito bem, como array do tipo ROM, são sempre do tipo estático, mesmo quando o declaramos de maneira a ele aparentemente ser do tipo dinâmico. Não existe muito mais o que falar sobre eles aqui. Isto por que, este tipo de array, onde tentativas de escrita, são consideradas um erro. E o código não é compilado. Ficamos sem mais coisas para se falar neste tópico. Assim vamos a um novo tópico. Onde iremos tratar de um outro tipo de array. Que é somente um pouco mais complicado. Isto devido ao fato de que podemos escrever nele.
Array tipo RAM
O pré-requisito para entender este array daqui, é de fato ter compreendido o array tipo ROM. Onde podemos ter a declaração sendo estática ou dinâmica. Porém, diferente do array tipo ROM, cujo conteúdo é constante, e o número de elementos presentes também é constante. No array tipo RAM, as coisas são um pouco mais complicadas. Isto por que, os números de elementos podem ou não ser constante. Assim como também o conteúdo presente em cada elemento, pode variar conforme o código venha a ser executado.
Bem, com estas primeiras palavras, você talvez esteja imaginando que este tipo de array é um pesadelo vivo. Porém, ele só exige um pouco mais de atenção, para que seja corretamente utilizado. Aqui é onde cada detalhe faz toda a diferença. Porém, existem alguns detalhes, relacionados aos arrays, aqui no MQL5, que eu gostaria que você os ignorasse por um tempo, meu caro leitor. Isto por que, existe um tipo especial de array, que tem como objetivo servir como um buffer. Isto falando de MQL5. Mas este tipo será melhor explicado em outro momento. Onde iremos falar de cálculos e programação voltada para ser utilizada no MetaTrader 5. Então por hora, o que será explicado aqui, não se aplica a estes arrays, cujo objetivo é servir como buffer de dados. O proposito aqui, e neste momento, é dar uma explicação geral, sobre utilização de arrays na programação. Não apenas voltada ao MQL5, mas a toda e qualquer linguagem de programação.
Ok, então vamos fazer o seguinte: Com base no último código visto no tópico anterior. Vamos remover a palavra reservada const, de ambas declarações. Ao fazermos isto, tiramos a limitação dos arrays. Porém, existe um detalhe muito importante a ser explicado. Isto quando fazemos a mudança, a fim de criar o código visto logo na sequência.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. char Ram_01[] = {72, 101, 108, 111, 33}; 07. char Ram_02[8] = {'H', 'e', 'l', 'o', '!'}; 08. 09. const uchar pos = 5; 10. 11. PrintFormat("%c%c%c%c%c%c", Ram_01[0], Ram_01[1], Ram_02[2], Ram_01[2], Ram_02[3], Ram_01[4]); 12. 13. PrintFormat("Contents of position %d of the RAM_02 array: %d", pos, Ram_02[pos - 1]); 14. PrintFormat("Contents of position %d of the RAM_01 array: %d", pos, Ram_01[pos - 1]); 15. } 16. //+------------------------------------------------------------------+
Código 03
Quando você executar este código 03, terá o mesmo resultado visto na imagem 03. Mas aqui existe uma diferença crucial. E esta é justamente o fato de que NÃO ESTAMOS LIDANDO COM UMA ROM. Mas sim com uma RAM. Isto nos permite modificar o código 03, a fim de conseguirmos criar o que é visto logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. char Ram_01[] = {72, 101, 108, 111, 33}; 07. char Ram_02[8] = {'H', 'e', 'l', 'o', '!'}; 08. 09. uchar pos = 5; 10. 11. PrintFormat("%c%c%c%c%c%c", Ram_01[0], Ram_01[1], Ram_02[2], Ram_01[2], Ram_02[3], Ram_01[4]); 12. 13. PrintFormat("Contents of position %d of the Ram_02 array: %d", pos, Ram_02[pos - 1]); 14. PrintFormat("Contents of position %d of the Ram_01 array: %d", pos, Ram_01[pos - 1]); 15. 16. Ram_02[pos - 1] = '$'; 17. PrintFormat("Contents of position %d of the Ram_02 array: %d", pos, Ram_02[pos - 1]); 18. 19. Ram_01[pos - 1] = '$'; 20. PrintFormat("Contents of position %d of the Ram_01 array: %d", pos, Ram_01[pos - 1]); 21. } 22. //+------------------------------------------------------------------+
Código 04
Este código 04 é muito curioso e de certa maneira até um pouco interessante. Isto pelo simples fato, de que nas linhas 16 e 19 estamos tentando modificar o valor presente em uma dada posição do array. Isto é um fato, que se bem compreendido, pode aguçar bastante a curiosidade dos mais ousados. Então, quando executarmos este código 04, teremos o resultado visto logo abaixo.
Imagem 04
Note que foi possível modificar os valores. Isto não seria permitido no caso de estarmos utilizando um array do tipo ROM. Neste momento você deve estar se perguntando uma coisa: Será que podemos mudar qualquer informação dentro do array? Bem, a resposta a esta pergunta é: Depende.
Observe o seguinte meu caro leitor: O array da linha seis, apesar de ser do tipo dinâmico, devido ao fato de não estamos indicando um índice de número de elementos para ele. Continua sendo estático. Isto por conta do fato de estamos iniciando-o na própria declaração. Já o array da linha sete, é totalmente estático. Porém o número de elementos possíveis dentro dele é maior do que o número de elementos que estamos declarando na inicialização do array.
Entendendo este fato, você pode dizer o seguinte: Então se usamos um índice, que aponte para algum elemento, podemos mudar o seu valor. Certo? Correto. Tanto que você poderia fazer uso de um código parecido com o mostrado abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. char r[10] = {72, 101, 108, 108, 111, 33}; 07. 08. string sz0; 09. 10. sz0 = ""; 11. for (uchar c = 0; c < ArraySize(r); c++) 12. sz0 = StringFormat("%s%03d, ", sz0, r[c]); 13. 14. Print(sz0); 15. 16. Print("Modifying a value..."); 17. 18. r[7] = 36; 19. 20. sz0 = ""; 21. for (uchar c = 0; c < ArraySize(r); c++) 22. sz0 = StringFormat("%s%03d, ", sz0, r[c]); 23. 24. Print(sz0); 25. } 26. //+------------------------------------------------------------------+
Código 05
Ao executar este código 05, o resultado seria o que podemos ver na imagem logo abaixo.
Imagem 05
Ou seja, de fato funciona. Podemos mudar qualquer valor, desde que o elemento acessado exista de fato dentro do array. Porém, esta linha 18, somente funcionou, por conta que na linha seis informamos que o array teria 10 elementos. Ok, acredito que tenha dado para entender esta primeira parte. Mas será que precisamos sempre trabalhar desta maneira? Ou seja, quando estamos declarando um array, precisamos logo na declaração informar quantos elementos, ou quais elementos deverá existir nele? De fato, esta é uma questão que gera muitas dúvidas em iniciantes. E novamente a resposta para isto é: Depende. Porém, e é bom que isto fique bem claro e nítido para você, meu caro leitor. Um array constante, ou seja, do tipo ROM, deverá SEMPRE, ter seus elementos, ou número de elementos declarados no momento da criação do array. Um detalhe, a declaração dos elementos neste caso é obrigatória. No entanto, declarar o número de elementos é opcional.
Esta regra é rígida e não aceita mudanças ou interpretações. Mas, com relação a arrays do tipo RAM, não existe de fato uma regra a ser seguida. Tudo depende, do proposito ou objetivo a ser alcançado. No entanto, declarar elementos em um array do tipo dinâmico, em um array que não seja do tipo ROM, ou seja, constante. Não é de fato algo comum de ser feito. Como acontece na linha seis do código 04. Isto por que, ao fazermos este tipo de coisa, estamos transformando aquele array, que em tese, seria dinâmico e um array estático. Mais ou menos como acontece no caso do array da linha sete do mesmo código 04.
Porém em termos de interpretação de código, e pelo ponto de vista da aplicação. Um array declarado como é mostrado na linha seis do código 04, poderia ser substituído por um como mostrado logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. char Ram_01[5], 07. pos = 5; 08. 09. Ram_01[0] = 72; 10. Ram_01[1] = 101; 11. Ram_01[2] = 108; 12. Ram_01[3] = 111; 13. Ram_01[4] = 33; 14. 15. PrintFormat("%c%c%c%c%c%c", Ram_01[0], Ram_01[1], Ram_01[2], Ram_01[2], Ram_01[3], Ram_01[4]); 16. 17. PrintFormat("Contents of position %d of the Ram_01 array: %d", pos, Ram_01[pos - 1]); 18. Ram_01[pos - 1] = '$'; 19. PrintFormat("Contents of position %d of the Ram_01 array: %d", pos, Ram_01[pos - 1]); 20. } 21. //+------------------------------------------------------------------+
Código 06
Note que aqui, neste código 06, temos agora na linha seis a declaração de um array estático. Ao fazermos isto, dizemos ao compilador, que precisamos que ele, compilador, venha a alocar uma faixa de memória para nós. Isto de maneira totalmente automática. Assim o compilador irá alocar, durante a compilação, um espaço na memória, suficientemente grande para conter a quantidade de elementos que estão sendo indicados. No caso, cinco elementos. E como o tipo é char, teremos cinco bytes alocados e disponíveis para uso imediato. Agora pense neste espaço alocado, como sendo uma variável de cinco bytes. Você pode usar a mesma da maneira como melhor lhe for conveniente. Também podemos alocar um número arbitrário. Por exemplo, se no lugar de cinco, visto na linha seis, colocamos 100, teríamos a criação do que seria uma variável de 100 bytes. Lembrando que a maior largura atualmente é de 8 bytes, ou 64 bits. Ou seja, poderíamos colocar pouco mais de 12 destas variáveis de 8 bytes, dentro deste array de 100 bytes.
De qualquer maneira, quando você executar este código 06, irá ver o que é mostrado logo abaixo.
Imagem 06
Agora note, que a inicialização, não foi feita na declaração do array, mas sim entre as linhas nove e treze. Isto funciona da mesma forma que a linha 18 neste código 06. Assim como foi feito nos códigos anteriores.
Porém, toda via e, entretanto, existe um pequeno detalhe aqui. Como o array está sendo criado de maneira estática. Caso você precise de mais espaço, por qualquer que venha a ser o motivo. Não conseguirá alocar mais espaço na memória. Isto durante a fase se execução do código. Por conta disto, arrays estáticos, são usados em situações muito especificas. Assim como arrays dinâmico. Mas se no lugar de definir um valor, para indicar o número de elementos no array. Como é visto na linha seis deste código 06. Fosse utilizado a linha vista logo abaixo.
char Ram_01[]
Teríamos a declaração de um array totalmente dinâmico. Agora preste muita atenção meu caro leitor. Ao fazermos isto, estamos dizendo ao compilador, que nós, programadores é que iremos tomar conta do array, alocando e liberando a memória conforme vai sendo necessário, ser feito. Porém assim que a linha nove for ser executada. Será gerado um erro. Isto por que, você estará tentando acessar uma memória que não foi alocada ainda. Este erro pode ser visto logo abaixo.
Imagem 07
Não é raro, em programas com muitas variáveis, termos a incidência deste tipo de erro. Porém, corrigir ele é muito simples e direto. Basta que venhamos a alocar a memória, ANTES de usar o array. E depois, quando já tivermos utilizado o array, venhamos a liberar a memória. Sendo está liberação, feita de maneira explicita, uma boa pratica de programação. Em alguns casos, mais simples, em códigos bem mais modestos e menos profissionais, deixamos de fazer esta liberação. Porém não é recomendado fazer isto. Já que normalmente a memória alocada não é liberada, somente por você ter deixado de usar aquela região de memória. Então comece fazendo as coisas da forma correta. Alocou memória, assim que não precisar mais dela, libere ela, para que não fique sujeito a erros bizarros durante a execução do código.
Bem, tendo dado está breve explicação sobre o que deve ser feito. Para corrigir o código e assim usar de fato um array dinâmico. Mudamos o código 06, para o código 07 visto logo na sequência.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. char r[]; 07. string sz0; 08. 09. PrintFormat("Allocated enough position for %d elements", ArrayResize(r, 10)); 10. 11. r[0] = 72; 12. r[1] = 101; 13. r[2] = 108; 14. r[3] = 111; 15. r[4] = 33; 16. 17. sz0 = ""; 18. for (uchar c = 0; c < ArraySize(r); c++) 19. sz0 = StringFormat("%s%03d, ", sz0, r[c]); 20. Print(sz0); 21. 22. Print("Modifying a value..."); 23. 24. r[7] = 36; 25. 26. sz0 = ""; 27. for (uchar c = 0; c < ArraySize(r); c++) 28. sz0 = StringFormat("%s%03d, ", sz0, r[c]); 29. Print(sz0); 30. 31. ArrayFree(r); 32. } 33. //+------------------------------------------------------------------+
Código 07
E aí está meu caro leitor, um código que de fato faz uso de um array puramente dinâmico. Note que ele se parece bastante com o código 05. Isto é proposital. Justamente para mostrar que podemos fazer a mesma coisa, só que de maneiras diferentes. E o resultado da execução deste código 07 é vista logo abaixo.
Imagem 08
Mas note, que nesta imagem 08, estou marcando algumas informações importantes. E quero que você, meu caro e estimado leitor, preste muita atenção ao que irei explicar. Pois é muito importante. Normalmente, programadores menos cuidadosos, ou cujo código, não será usado para propósitos críticos. Simplesmente usam a memória sem de fato, a inicializar adequadamente. Este tipo de coisa, gera uma quantidade absurda de erros difíceis de serem detectados. Mesmo por programadores extremamente experientes. Aqui estou mostrando uma destas falhas. Note que a memória foi alocada na linha nove do código 07. Entre as linhas 11 e 15, atribuímos valores a algumas posições da memória alocada. Porém, quando fazemos a leitura, procurando obter o conteúdo presente na memória, veja que temos uma informação estranha presente ali. Esta informação, é chamada de lixo, já que ela existe na memória, porém não devia estar ali.
Mas a parte importante aqui é justamente a linha 22. Já que ela nos diz que naquele momento estaremos modificando a memória. E isto é feito na linha 24. No entanto, ao fazermos uma nova leitura da memória. Aparentemente é como se o programa, soubesse o futuro. E antes de que tenhamos aplicado o valor aquela posição de memória, o valor tivesse surgido do nada. Ali, como por mágica.
Bem, e por que isto ocorreu? Não é nenhum truque de mágica, ou viagem no tempo. O motivo, está diretamente ligado ao fato de que a memória alocada, não está de fato sobre seu controle. Quem faz a alocação da memória é o sistema operacional. E o que tem ali, pode ser qualquer coisa. Desde restos de informações de outros programas, o que é chamado de lixo. Até mesmo um monte de zeros. O conteúdo é sempre aleatório. Porém, se o sistema operacional, alocar uma mesma posição de memória, para duas execuções consecutivas. Onde a memória foi alocada, liberada e logo depois alocada novamente. Que pode ser de um mesmo código ou de outro qualquer. A possibilidade de haver lixo ali, é muito grande.
E se você, imaginar que o conteúdo ali seja este ou aquele, pode acabar tendo um problema realmente difícil de resolver. Por isto, NUNCA, mas NUNCA MESMO, ache que a memória está com um dado conteúdo presente nela. NUNCA. Sempre que alocar uma memória, LIMPE a região, ou no mínimo inicialize a mesma completamente. Existem diversas formas de se fazer isto no MQL5. Eu mesmo gosto de usar uma chamada da biblioteca padrão bastante simples e eficiente par tal coisa. Assim, o código 07, corrigido é mostrado logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. char r[]; 07. string sz0; 08. 09. PrintFormat("Allocated enough position for %d elements", ArrayResize(r, 10)); 10. 11. ZeroMemory(r); 12. 13. r[0] = 72; 14. r[1] = 101; 15. r[2] = 108; 16. r[3] = 111; 17. r[4] = 33; 18. 19. sz0 = ""; 20. for (uchar c = 0; c < ArraySize(r); c++) 21. sz0 = StringFormat("%s%03d, ", sz0, r[c]); 22. Print(sz0); 23. 24. Print("Modifying a value..."); 25. 26. r[7] = 36; 27. 28. sz0 = ""; 29. for (uchar c = 0; c < ArraySize(r); c++) 30. sz0 = StringFormat("%s%03d, ", sz0, r[c]); 31. Print(sz0); 32. 33. ArrayFree(r); 34. } 35. //+------------------------------------------------------------------+
Código 08
Ao executar este código 08, você terá o que é visto logo na sequência.
Imagem 09
Note que a única diferença entre a imagem 08 e a imagem 09, é justamente aquela posição da memória. Onde na primeira execução tínhamos a presença de lixo ali. Já quando adicionamos a linha 11, que é vista no código 08. Aquele tipo de erro, onde lixo estava sendo, ou poderia ser utilizado, deixa de acontecer. Simples assim. Mas como eu disse existem outras funções que tem o mesmo objetivo, no MQL5. Tudo é uma questão de escolha e objetivo a ser cumprido.
Considerações finais
Neste artigo, que de fato, contém uma base de algo muito mais complicado, do que o mostrado aqui. Demonstrei, como você poderia ver um array de maneira um pouco mais profissional. Se bem que talvez você não tenha conseguido pegar o que eu quero mostrar. Já que de fato, este tipo de coisa, é muito mais complicada de explicar assim, do que todo e qualquer outro tema em programação. Mas de qualquer forma, acredito ter alcançado parte do objetivo principal. Já que expliquei como podemos criar uma memória ROM dentro da memória RAM. E também vimos, como é feita a escolha, de que estaremos usando um array dinâmico ou um array estático.
Porém vale mencionar, o fato de que, você NUNCA deve supor algo, quando o assunto é array, ou acesso a memória. Já que elementos não inicializados, podem conter lixo. E usar lixo em um código, pode trazer sérios dados aos resultados esperados, ou criar dificuldade em resolver problemas de interação entre programas diferentes.
De qualquer maneira, no anexo, você terá acesso aos códigos vistos aqui. Isto para que possa estudar e praticar, com algo que de fato funciona. Tanto no quesito de gerar falhas de execução, a fim de que você aprenda como lidar com elas. Como também, conceitos relacionados a utilização de arrays em atividades mais recreativas.
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso