English Русский Español Deutsch 日本語
preview
Do básico ao intermediário: Array (I)

Do básico ao intermediário: Array (I)

MetaTrader 5Exemplos | 12 outubro 2024, 15:27
184 0
CODE X
CODE X

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 e String (III), expliquei e mostrei com um código voltado para o nível atual de conhecimento demonstrado até aqui. Como a biblioteca padrão consegue traduzir valores binários em um valor decimal, octal e hexadecimal. Além é claro a de criar uma representação binária em formato de string. Isto para que pudéssemos visualizar o resultado facilmente.

Além desta questão básica. Também foi demonstrado como poderíamos definir uma largura para nossa senha, com base em uma frase secreta. E por uma feliz coincidência, a senha ou password resultante, acabou tendo uma sequência de caracteres repetido. Algo magnifico. Já que não era este o objetivo real. De fato, foi apenas uma feliz coincidência. Mas que irá me proporcionar, uma ótima oportunidade para explicar diversos outros conceitos e pontos relacionados ao assunto arrays e strings.

Alguns podem estar imaginando que irei abordar o funcionamento de cada função ou procedimento contido da biblioteca padrão. Mas este não é de fato meu objetivo. Isto por que o meu real objetivo é mostrar os conceitos por trás de cada decisão. Assim, você pode tomar suas próprias decisões, baseadas no tipo de problema que precisa ser resolvido. Como ainda estamos em um nível bem baixo. Mas já contando com algumas possibilidades reais em termos de programação. Podemos começar a aplicar, alguns conceitos um pouco mais avançados.

Isto além de tornar a codificação mais simples para que eu a faça. Tornará você, meu caro leitor, apto a ler códigos um pouco mais elaborados. Mas não precisa ficar com receio do que será visto aqui. Irei introduzir as mudanças aos poucos, de modo que você se acostume e consiga ler meus códigos sem problema. Já que tenho o costume de minimizar, ou compactar as expressões de uma maneira, que pode ser confuso, para quem esteja começando.

De qualquer forma, vamos começar este artigo, falando a respeito do que foi visto no artigo anterior. Ou seja, vamos aprender, uma de tantas maneiras possíveis de evitar, justamente aquilo que foi o resultado das fatorações para criar uma senha a partir de uma frase secreta.


Uma entre tantas soluções

Muito bem. Vamos começar tornando o código um pouco mais agradável. Isto na falta de uma frase melhor. O código original é mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const string sz_Secret_Phrase = "Um pequeno jabuti xereta viu dez cegonhas felizes";
07. 
08.     Print("Result:\n", PassWord(sz_Secret_Phrase, 8));
09. }
10. //+------------------------------------------------------------------+
11. string PassWord(const string szArg, const uchar SizePsw)
12. {
13.     const string szCodePhrase = ")0The!1quick@2brown#3fox$4jumps%5over^6the&7lazy*8dog(9";
14. 
15.     uchar   psw[],
16.             pos,
17.             i = 0;
18. 
19.     ArrayResize(psw, SizePsw);
20.     ArrayInitialize(psw, 0);
21.     for (int c = 0; szArg[c]; c++)
22.     {
23.         pos = (uchar)(szArg[c] % StringLen(szCodePhrase));
24.         psw[i++] += (uchar)szCodePhrase[pos];
25.         i = (i == SizePsw ? 0 : i);
26.     }
27.     
28.     for (uchar c = 0; c < SizePsw; c++)
29.         psw[c] = (uchar)(szCodePhrase[psw[c] % StringLen(szCodePhrase)]);
30. 
31.     return CharArrayToString(psw);
32. }
33. //+------------------------------------------------------------------+

Código 01

Porém, ao meu ver este código é um tanto quanto desagradável. Isto por que as variáveis declaradas nas linhas 16 e 17, são usadas apenas no laço da linha 21. Porém, se por qualquer motivo, precisarmos de uma variável com o mesmo nome, ou de tipo diferente, teremos um trabalho extra apenas para ajeitar o código. No entanto, como foi visto nos artigos anteriores. Podemos declarar variáveis dentro de um laço FOR.

Agora preste atenção meu caro leitor. Ao declararmos mais de uma variável, voltada a ser utilizada somente no laço FOR. Precisamos que todas elas sejam do mesmo tipo. NÃO É POSSIVEL, declarar e inicializar variáveis de tipos diferentes, como sendo a primeira expressão do comando FOR. Bem, com isto temos que fazer uma pequena escolha. Como as variáveis pos e i, que estão sendo declaradas nas linhas 16 e 17, são do tipo uchar. E a variável c, declarada no comando for é do tipo int. Podemos colocar as outras duas como sendo do tipo int, ou mudar a variável c, para o tipo uchar. De qualquer maneira, ao meu ver, não faz sentido uma frase com mais de 255 caracteres. Sendo assim, podemos procurar um meio termo, colocando todas as três variáveis como sendo do tipo ushort. Já que elas são utilizadas apenas como índice de acesso. Dada está explicação. O código 01 é modificado para o código 02. Que pode ser visto logo na sequência.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const string sz_Secret_Phrase = "Um pequeno jabuti xereta viu dez cegonhas felizes";
07. 
08.     Print("Result:\n", Password(sz_Secret_Phrase, 8));
09. }
10. //+------------------------------------------------------------------+
11. string Password(const string szArg, const uchar SizePsw)
12. {
13.     const string szCodePhrase = ")0The!1quick@2brown#3fox$4jumps%5over^6the&7lazy*8dog(9";
14. 
15.     uchar psw[];
16. 
17.     ArrayResize(psw, SizePsw);
18.     ArrayInitialize(psw, 0);
19.     
20.     for (ushort c = 0, pos, i = 0; szArg[c]; c++, i = (i == SizePsw ? 0 : i))
21.     {
22.         pos = (ushort)(szArg[c] % StringLen(szCodePhrase));
23.         psw[i++] += (uchar)szCodePhrase[pos];
24.     }
25. 
26.     for (uchar c = 0; c < SizePsw; c++)
27.         psw[c] = (uchar)(szCodePhrase[psw[c] % StringLen(szCodePhrase)]);
28. 
29.     return CharArrayToString(psw);
30. }
31. //+------------------------------------------------------------------+

Código 02

Apesar da aparente confusão que pode ter se tornado este código 02. Ele continua fazendo a mesma coisa que era feito no código 01. Porém quero chamar a sua atenção para a linha 20. Observe que na primeira expressão, agora estamos declarando todas as variáveis que serão utilizadas no laço. E somente neste laço. No entanto, note como está a terceira expressão do comando for. Note que neste caso, não seria possível fazer este tipo de ajuste na variável i, sem utilizar o operador ternário. Mas é preciso ficar atento, ao fato de que este ajuste, apenas resolve a questão de manter o índice dentro do array. Já que o incremento está sendo feito na linha 23.

Apesar desta mudança, o resultado é exatamente o mesmo de antes. Ou seja, ao executar o código, você irá ver no terminal algo parecido com a imagem logo abaixo.

Imagem 01

Agora vamos pensar um pouco. Estamos uma repetição de símbolos na string de saída, justamente por conta de que, na linha 27 estaremos apontando para o mesmo ponto na string szCodePhrase. Ou seja, ao reduzirmos os valores para dentro do limite da string definida na linha 13. Estamos sempre apontando para o mesmo local. Mas, e é aqui onde entra o grande detalhe, se somarmos a atual posição com a antiga, poderemos ter um novo índice. Totalmente diferente do anterior. E como a string da linha 13, não temos repetição de símbolos. A string de saída, que seria o nosso password, não teria caracteres repetidos.

É importante notar uma coisa aqui. Este tipo de coisa que estou mostrando, não funciona sempre. Isto devido ao fato de que a quantidade de símbolos presentes na string da linha 13, pode ser um número inadequado. Ou em outra situação, os valores acabam em um ciclo perfeito. Isto por que, de fato, temos um ciclo de caracteres ou símbolos sendo declarados na linha 13. Onde o primeiro símbolo que é um fecha parênteses se liga ao último símbolo que é o valor nove. Seria como uma cobra mordendo a própria calda.

Muitos, que não são programadores não entendem isto. Mas este tipo de coisa sempre acontece, de uma forma ou de outra, quando estamos trabalhando com programação.

Ok, agora que expliquei o que iremos fazer, que tal apreciarmos o código? Este é mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const string sz_Secret_Phrase = "Um pequeno jabuti xereta viu dez cegonhas felizes";
07. 
08.     Print("Result:\n", Password(sz_Secret_Phrase, 8));
09. }
10. //+------------------------------------------------------------------+
11. string Password(const string szArg, const uchar SizePsw)
12. {
13.     const string szCodePhrase = ")0The!1quick@2brown#3fox$4jumps%5over^6the&7lazy*8dog(9";
14. 
15.     uchar psw[];
16. 
17.     ArrayResize(psw, SizePsw);
18.     ArrayInitialize(psw, 0);
19.     
20.     for (ushort c = 0, pos, i = 0; szArg[c]; c++, i = (i == SizePsw ? 0 : i))
21.     {
22.         pos = (ushort)(szArg[c] % StringLen(szCodePhrase));
23.         psw[i++] += (uchar)szCodePhrase[pos];
24.     }
25. 
26.     for (uchar c = 0; c < SizePsw; c++)
27.         psw[c] = (uchar)(szCodePhrase[((c ? psw[c - 1] : 0) + psw[c]) % StringLen(szCodePhrase)]);
28. 
29.     return CharArrayToString(psw);
30. }
31. //+------------------------------------------------------------------+s

Código 03

Este tipo de coisa é muito interessante. Veja que mudei quase nada no código. Apenas modifiquei o que seria a linha 27. Fazendo algo muito parecido com o que foi feito na terceira expressão do laço for. Que pode ser visto na linha 20. Mas antes de falar sobre isto, vamos ver o resultado. Este pode ser analisado logo abaixo.

Imagem 02

Perceba que agora já não temos a mesma repetição de antes. Porém as coisas podem ficar ainda melhores. E isto mudando apenas uma única coisa no código 03. Agora como foi explicado nos artigos anteriores, este operador ternário, da linha 27, funciona como um comando IF. Por conta disto, o primeiro valor que estará sendo calculado não sofre nenhum ajuste. No entanto, todos os demais valores irão sofrer um ajuste dependendo do valor usado no índice anterior do array. Preste atenção. O valor do array a ser utilizado nesta correção NÃO É o que foi calculado pelo laço da linha 20. Ele é o que foi obtido, da string definida na linha 13. Assim para saber o exato valor, é necessário recorrer a tabela ASCII. E somar este com o valor que foi calculado no laço da linha 20. Parece um tanto quanto confuso. Mas é bem simples, se você parar e pensar um pouco.

Porém, quero chamar a sua atenção para o valor zero, que está sendo usado no operador ternário. Com o primeiro índice, não sofre nenhuma mudança, justamente por conta deste valor. O que aconteceria se fosse utilizado um outro valor ali? Bem, suponhamos que esta linha 27, seja modificada pela linha vista logo abaixo.

psw[c] = (uchar)(szCodePhrase[((c ? psw[c - 1] : 5) + psw[c]) % StringLen(szCodePhrase)]);

O resultado seria muito diferente, como você pode observar na imagem logo a seguir.

Imagem 03

Interessante. Então com uma simples mudança, conseguimos gerar algo que muitos consideram uma senha forte. E para isto, usamos simples cálculos e duas frases fáceis de lembrar. E olha que fizemos tudo isto, usando um nível de conhecimento em programação, que eu considero básico. Nada mal para um iniciante. Então meu caro leitor, divirta-se estudando e experimentando novas possibilidades. Já que aqui mostrei apenas algo muito simples e básico. Coisa que um programador mais experiente faria em questão de minutos.

Beleza, esta foi a parte fácil de demonstração sobre uso de arrays. Porém ainda não terminou. Antes que possamos dar novos passos em direção a algo mais elaborado e complexo. Precisamos falar de outros detalhes relacionados aos arrays. Mas para isto, vamos a um novo tópico.


Tipos de dados e sua relação com os arrays

Um dos tópicos mais complicados, confusos e difíceis de dominar em programação, é justamente o título deste tópico. Talvez, e muito provavelmente, você meu caro leitor, não tenha a devida noção do quanto este tema é complicado. Alguns se consideram bons programadores, porém não fazem a mínima ideia de como as coisas estão correlacionadas. E por conta disto, dizem que certas coisas não são possíveis, ou que são mais difíceis de serem feitas, do que realmente são na prática.

Conforme este tema for sendo assimilado por você, meu caro leitor. Você irá naturalmente começar a entender diversos outros temas. Que aparentemente não estão correlacionados. Mas bem lá no fundo, são todos a mesma coisa.

Para começar vamos pensar em uma memória de computador. Não interessa se o processador é de 8, 16, 32, 64 ou qualquer valor exótico para o número de bits. Como por exemplo 48 bits. Isto definitivamente não interessa. Da mesma forma, não interessa se estamos lidando com valor binário, octal, hexadecimal, ou qualquer outra base numérica. Isto também não faz diferença. O que importa de verdade, é como as estruturas de dados estão sendo configuradas, ou construídas. Por exemplo: Quem disse que um byte precisa ter oito bits? E por que oito bits? Será que ele não poderia ter dez bits, ou doze?

Talvez isto que estou falando, pode não estar fazendo muito sentido. Isto por que, é de fato muito difícil, condensar décadas de experiência em algo que todos possam entender, tendo como foco um programador iniciante. No entanto, sem entrar em certos conceitos, antes da hora, falar sobre certas coisas é bem complicado. Porém, com o que já foi mostrado nos artigos anteriores. Podemos fazer uma pequena brincadeira aqui. Para isto, vamos trabalhar com array de um tipo qualquer, e alguma variável de um outro tipo qualquer. Entretanto, existe uma pequena regra a ser seguida. O tipo de dado, usado no array NÃO PODE SER O MESMO da variável. E mesmo assim, podemos fazer com que ambos conversem entre si e tenham o mesmo tipo de valor. Isto desde que sigamos algumas regras simples.

Hum, parece algo complicado, que exige muito mais conhecimento de programação. Mas será mesmo? Vamos experimentar para ver se, isto é, de fato verdade. Para tornar as coisas ainda mais divertidas. Vamos usar aquela função vista no artigo anterior. Onde podíamos converter valores binários, para um outro tipo de representação.

Ok. Parece ser uma boa ideia. E para tornar a coisa bem extensiva. Já que iremos usar muito aquele tipo de implementação, para explicar diversas coisas. Vamos colocar aquela função em um arquivo de cabeçalho. Assim irá nascer o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. string ValueToString(ulong arg, char format)
05. {
06.     const string szChars = "0123456789ABCDEF";
07.     string  sz0 = "";
08. 
09.     while (arg)
10.         switch (format)
11.         {
12.             case 0:
13.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg % 10)], sz0);
14.                 arg /= 10;
15.                 break;
16.             case 1:
17.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0x7)], sz0);
18.                 arg >>= 3;
19.                 break;
20.             case 2:
21.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0xF)], sz0);
22.                 arg >>= 4;
23.                 break;
24.             case 3:
25.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0x1)], sz0);
26.                 arg >>= 1;
27.                 break;
28.             default:
29.                 return "Format not implemented.";
30.         }
31. 
32.     return sz0;
33. }
34. //+------------------------------------------------------------------+

Código 04

Agora um detalhe importante: Como este código 04, é um arquivo de cabeçalho, que estará presente, e quero deixá-lo disponível apenas para os scripts de tutorial. O mesmo estará em uma pasta, dentro da pasta scripts. Como já expliquei antes, o que isto irá representar para qualquer coisa criada aqui. Não vou voltar a falar sobre este tema. Podendo assim seguir e frente. Perfeito. Note o seguinte detalhe aqui, meu caro leitor. Todos os valores que iremos converter devem ser pensados como valores sem sinal. Isto até que venhamos a corrigir este pequeno detalhe na função vista no código 04.

Uma vez feito isto, podemos testar se as coisas estão funcionando. Para isto, usaremos um código bem simples, que pode ser observado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     ushort value = 0xCADA;
09. 
10.     PrintFormat("Translation via standard library.\n" +
11.                 "Decimal: %I64u\n" +
12.                 "Octal  : %I64o\n" +
13.                 "Hex    : %I64X",
14.                 value, value, value
15.                );
16.     PrintFormat("Translation personal.\n" +
17.                 "Decimal: %s\n" + 
18.                 "Octal  : %s\n" +
19.                 "Hex    : %s\n" +
20.                 "Binary : %s",
21.                 ValueToString(value, 0),
22.                 ValueToString(value, 1),
23.                 ValueToString(value, 2),
24.                 ValueToString(value, 3)
25.                );
26. }
27. //+------------------------------------------------------------------+

Código 05

Ao executar este código, o resultado é o que podemos observar logo na imagem abaixo.

Imagem 04

Definitivamente podemos ver que funciona. Sendo assim, já podemos começar a brincar com arrays e variáveis de tipos diferentes. Isto para que você possa começar a compreender uma coisa muito curiosa, que só acontece em certas linguagens de programação. Para isto, vamos iniciar com uma mudança no próprio código 05. Então este será, o código que irei chamar de: MARCO ZERO. O mesmo pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uchar array[] = {0xCA, 0xDA};
09.     ushort  value = 0;
10. 
11.     value = (array[0] << 8) | (array[1]);
12.     
13.     PrintFormat("Translation personal.\n" +
14.                 "Decimal: %s\n" + 
15.                 "Octal  : %s\n" +
16.                 "Hex    : %s\n" +
17.                 "Binary : %s",
18.                 ValueToString(value, 0),
19.                 ValueToString(value, 1),
20.                 ValueToString(value, 2),
21.                 ValueToString(value, 3)
22.                );
23. }
24. //+------------------------------------------------------------------+

Código 06

Agora, quero pedir uma coisa a você, meu caro leitor. Peço para que deixe de lado qualquer distração, ou coisa que lhe tire de alguma forma a sua atenção. E quero que você foque inteiramente no que iremos começar a ver, deste momento em diante. Pois o que começarei a explicar agora é algo muito confuso, para muitos programadores iniciantes. Porém, não qualquer tipo de programador. Mas sim para aqueles que fazem uso de determinadas linguagens de programação, entre elas o MQL5.

Antes de falarmos qualquer coisa, vamos ver o resultado da execução do código 06. Este pode ser observado logo abaixo.

Imagem 05

Isto que está sendo mostrado aqui, neste código 06, é a base para uma enorme quantidade de coisas. Que se você conseguir entender, ao estudar este código 06. Conseguirá compreender todas as demais, coisas, que irão surgir, sem nenhum problema. Isto por que, muitas delas derivam de alguma maneira do que este código 06 está fazendo.

Olhando pela primeira vez, talvez você não consiga perceber o quanto este código simples, é de fato complicado. Ou o que dá para fazer, somente pelo simples fato, de que este código 06 pode ser implementado. Então vamos com calma. E para quem já sabe, nada do que será explicado irá ser novidade. Mas para quem não sabe, o que será explicado aqui pode ser muito confuso.

Ok, talvez eu tenha dado um passo meio que grande aqui. Então vamos voltar um pouco. Começando pelo seguinte: Qual parte deste código 06, você meu caro leitor, não consegue compreender, apenas tendo como base o que já foi explicado até aqui? Muito provavelmente seja as linhas oito e onze. Bem, de fato, estas linhas são algo que para quem está começando. Não faz muito sentido. Se bem que nos códigos anteriores, neste mesmo artigo, vimos algo muito parecido. Como você pode observar ao olhar o código 03 nas linhas 15, 20, 23 e 27.

No entanto, aqui no código 06, as coisas funcionam de uma maneira um pouco diferente. Mas não totalmente diferente. Isto por que, eu talvez tenha cometido um erro. Que foi utilizar arrays, antes de os explicar de maneira adequada. Por conta disto, peço desculpas a você. Que agora pode estar um tanto quanto confuso vendo as coisas acontecerem como pode ser observado na imagem 05, quando executamos o código 06.

Então vamos começar da maneira correta, e de um modo mais simples. Começando pela linha 11 deste código 06. O que temos ali é o equivalente ao que pode ser visto na linha de código, logo abaixo.

    value = (0xCA << 8) | (0xDA);

Talvez olhando assim seja um pouco complicado. Apesar de já ter sido explicado como o operador de deslocamento funciona. De qualquer forma, vamos recorrer a uma ajuda visual. Isto deixará as coisas bem mais simples de se entender.

Imagem 06

Aqui cada retângulo em vermelho representa um byte, ou um valor do tipo uchar. E cada retângulo em azul representa uma variável. As setas indicam as movimentações que foram feitas no meio do caminho. Ou seja, nesta imagem 06 estamos mostrando, como o valor da variável value foi criado na linha 11. Deixe-me ver se entendi direito. Você está me dizendo, que apesar de value ser do tipo ushort, podemos colocar valores do tipo uchar dentro dela? Isto a ponto de criar um novo valor? É isto mesmo meu caro leitor. Porém a coisa não se limita a somente isto. Mas vamos com devagar para que o conceito seja muito bem compreendido.

Como você já deve saber, a região de memória que estamos criando na linha oito, é uma região constante. Porém não é somente isto. Como estamos iniciando os valores nesta região de memória, temos ali, o que você poderia pensar como sendo um cartucho de memória ROM. Tipo aqueles antigos cartuchos utilizados em vídeo games.

Imagem 07

Apesar de parecer estranho falarmos em criar uma memória ROM dentro da memória RAM. Esta linha oito de fato está fazendo exatamente isto.

Mas espere um pouco. Qual é o tamanho da memória ROM criada nesta linha oito? Isto depende meu caro leitor. E não estou dado esta resposta para lhe sacanear. Estou dizendo isto de maneira bastante sincera. Porém existe uma função na biblioteca padrão que nos diz qual o tamanho do bloco alocado. Lembre-se de que um array é uma string. Porém uma string é um array especial, como foi explicado antes. Mas diferente dos arrays mostrados nos códigos anteriores. Onde criamos um modelador de senha, a partir de frases simples. Este array construído aqui no código 06, é de fato um array puro. Ou seja, ele não é uma string. Mas um array voltado a representar qualquer tipo de valor. Porém, devido ao fato de que estamos declarando-o como sendo um array do tipo uchar. Limitamos o range que podemos colocar dentro dele. Mas, e é aí onde as coisas começam a complicar. Podemos usar um outro tipo maior, para nos dizer qual é o valor presente no array.

Para fazer isto, devemos usar um tipo que possa conter tantos bits quantos os que existe no array. É isto que a imagem 06 está querendo dizer. Já que a região em azul, seria o conjunto de todos os bits que estão no array. E para deixar isto mais claro, vamos colocar um pouco mais de informação na linha oito e ver o que acontece. Porém para que as coisas continuem simples. Precisamos mudar o código como mostrado abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uchar array[] = {0xCA, 0xDA, B'10101011', 250, 0x81};
09.     ulong  value = 0;
10. 
11.     for (uchar c = 0; c < array.Size(); c++)
12.         value = (value << 8) | (array[c]);
13. 
14.     PrintFormat("Translation personal.\n" +
15.                 "Decimal: %s\n" + 
16.                 "Octal  : %s\n" +
17.                 "Hex    : %s\n" +
18.                 "Binary : %s",
19.                 ValueToString(value, 0),
20.                 ValueToString(value, 1),
21.                 ValueToString(value, 2),
22.                 ValueToString(value, 3)
23.                );
24. }
25. //+------------------------------------------------------------------+

Código 07

Sim eu sei, isto que está sendo feito neste código 07, parece uma loucura completa. Mas veja o resultado, que iremos ter, ao executar este código. Isto é mostrado logo abaixo.

Imagem 08

Isto sim, você pode dizer que é muito doido. Mas como você pode notar, meu caro leitor. Funciona. Ou seja, misturamos em um array, valores binários, valores hexadecimais e valores decimais. E no final conseguimos montar um pequeno bloco ROM contendo, algum tipo de informação. Mas a parte mais maluca mesmo não é esta que estamos vendo aqui. Isto daqui é apenas a ponta do topo de um gigantesco iceberg.

Mas antes de aprofundar um pouco mais, vamos entender o que aconteceu, e quais limitações e cuidados que precisamos tomar ao lidar com este tipo de coisa.

Você pode ter notado, que na linha, apenas adicionei novos dados. Ok, mas qual é o número máximo de dados que podemos colocar ali? A resposta é INFINITOS DADOS. Ou até onde seu equipamento permitir. Já que na prática, a quantidade de coisas que podemos colocar ali, irá depender da capacidade de armazenamento que seu computador em armazenar dados. Porém, diferente do fato de podemos colocar uma quantidade quase ilimitada de dados na linha oito. A mesma coisa não acontece na variável value. Ali temos um limite máximo de bits que podemos colocar. Como eu queria permitir a você meu caro leitor, experimentar isto de uma forma mais liberal. Coloquei o limite máximo que atualmente é possível fazer no MQL5. Ou seja, 64 bits. Ou oito bytes. Isto significa que podemos colocar somente oito bytes na variável value? Não, meu caro leitor. Isto na verdade significa que depois de completar 64 bits, qualquer outra nova informação irá fazer com que as antigas sejam removidas. Este tipo de coisa gera um modelo de fluxo de dados que iremos ver futuramente.

Mas, é importante você observar que temos capacidade de colocar, no máximo, 64 bites em uma única variável. Porém isto não significa que podemos colocar oito valores. E é aqui onde as coisas começam a complicar para quem caiu direto neste artigo. E não viu os artigos anteriores, ou não praticou o que foi mostrado lá.

Antes de falarmos sobre o laço presente na linha 11 e o que está acontecendo na linha 12. Vamos mudar só um pequeno detalhe neste código 07. Isto para tornar claro, o conceito de quantidade de informações em um array. O detalhe a ser modificado é visto na linha de código logo abaixo.

const ushort array[] = {0xCADA, B'1010101111111010', 0x81};

Note que agora, olhando esta linha mostrada acima, o nosso array tem, não mais cinco elementos. Mas sim, três elementos. E é importante você notar que apesar desta mudança no número de elementos. Continuamos usando quase a mesma quantidade de memória. Se bem que agora temos 8 bits, sendo desperdiçados na memória. Isto por que, diferente do que existe de fato no código 07, onde cada byte está sendo integralmente utilizado. Aqui nesta nova estrutura, o último valor visto no array, está usado apenas 8 dos 16 bits disponíveis para ele. Sei que parece um desperdício aceitável. Mas iremos falar mais sobre isto em outros momentos. Só quero que você perceba que o tipo de dado usado influencia no consumo de memória. Assim como também muda a forma como seu código as vezes irá trabalhar.

No entanto, um caso pior ainda, ocorreria se você, por ventura vier a utilizar algo parecido com a linha vista abaixo.

const int array[] = {0xCA, 0xDA, B'10101011', 250, 0x81};

Sei que muita gente não se preocupa em usar um tipo inadequado em algumas variáveis. Mas apesar de aparentemente não haver, e no caso atual, não existe, nenhum problema em usar esta linha mostrada acima, no código 07. Agora você não mais está desperdiçando 8 bits de memória. Mas sim 16 bits de memória por elemento no array. Como são 5 elementos o desperdício é de 80 bits, ou 10 bytes. O que é mais que a largura da senha que estamos usando no começo do artigo.

Novamente, esta quantidade de memória jogada fora parece ser pouco. Visto que hoje em dia temos computadores com mais de 32 gigabytes de memória. E apesar deste desperdício e de uma possível falha que pode ocorrer. No nosso atual cenário, isto não irá mudar o comportamento do código. Visto o que acontece nas linhas 11 e 12. Então vamos entender o que acontece nestas duas linhas.

Aqui estamos dizendo para o código, que a cada elemento presente no array, queremos que o valor presente na variável value, seja deslocado oito bits para a esquerda. Dando assim espaço para o novo elemento entrar. Isto é o que acontece na linha 12. Mas está linhas é orientada a usar um determinado elemento no array. O elemento em questão é indicado pela variável c. Agora, como sabemos quantos elementos existe no array? Ali na linha 11, na segunda expressão que controla a finalização do laço, temos esta indicação. Isto que estamos fazendo aqui, é usando uma chamada da biblioteca padrão do MQL5.

Está chamada, vista na linha 11, equivale a utilizar a função ArraySize. Ou seja, desta forma que conseguimos saber quantos elementos existem no array. Independentemente do número de bits que cada elemento esteja de fato utilizando.

Para experimentar este tipo de coisa, basta modificar o código de forma que ele fique como mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uchar array[] = {0xCA, 0xDA, B'10101011', 250, 0x81};
09.     ulong  value = 0;
10. 
11.     for (uchar c = 0; c < array.Size(); c++)
12.         value = (value << 8) | (array[c]);
13. 
14.     PrintFormat("Translation personal.\n" +
15.                 "Decimal: %s\n" + 
16.                 "Octal  : %s\n" +
17.                 "Hex    : %s\n" +
18.                 "Binary : %s",
19.                 ValueToString(value, 0),
20.                 ValueToString(value, 1),
21.                 ValueToString(value, 2),
22.                 ValueToString(value, 3)
23.                );
24.     Print("Number of elements in the array: ", ArraySize(array));
25. }
26. //+------------------------------------------------------------------+

Código 08

Com isto, ao executar este código 08, você irá ver a quantidade de elementos presentes no array. Como mostrado na imagem abaixo, na região demarcada.

Imagem 09


Considerações finais

Bem, meu caro leitor, neste artigo, já tem muita coisa para você estudar e assimilar. Por conta disto, vou lhe dar um tempo para que você estude e pratique o que foi mostrado aqui. Procurando assim entender estes primeiros conceitos ligados a questão de utilização de arrays. Se bem que neste artigo, os arrays utilizados são do tipo ROM. Desta forma, não é possível modificar o conteúdo dos mesmos. Mas mesmo assim, é muito importante que você tente ao máximo compreender o que foi explicado aqui. Sei que este material é muito complicado de ser digerido assim, de uma hora para outra. Mas procure se esforçar ao máximo e se empenhar ainda mais em busca de um entendimento sobre o que está sendo mostrado nestes artigos. Principalmente este daqui.

Entender os demais artigos, irá lhe ajudar bastante para que você consiga se tornar um programador de excelência. E como agora o material irá ficar cada vez mais complexo. Você irá ser exigido cada vez mais. Então não desanime pelas dificuldades que este material irá lhe trazer. Procure praticar e use os anexos para entender os pontos que não mostro aqui. Porém aparecem sendo comentados no artigo. Como as modificações que foram ditas, mas com resultados não mostrados. É muito importante que você entenda o que aquelas modificações estão fazendo na memória. Então divirta-se com os arquivos presentes no anexo. 

Arquivos anexados |
Anexo.zip (3.74 KB)
Técnicas do MQL5 Wizard que você deve conhecer (Parte 22): GANs Condicionais Técnicas do MQL5 Wizard que você deve conhecer (Parte 22): GANs Condicionais
Redes Generativas Adversariais são uma combinação de Redes Neurais que treinam entre si para obter resultados mais precisos. Adotamos o tipo condicional dessas redes ao buscarmos uma possível aplicação na previsão de séries temporais financeiras dentro de uma Classe de Sinais de Expert.
Técnicas do MQL5 Wizard que você deve conhecer (Parte 21): Testando com Dados do Calendário Econômico Técnicas do MQL5 Wizard que você deve conhecer (Parte 21): Testando com Dados do Calendário Econômico
Os dados do Calendário Econômico não estão disponíveis para testes com Expert Advisors no Strategy Tester, por padrão. Vamos explorar como bancos de dados poderiam ajudar a contornar essa limitação. Portanto, neste artigo, exploramos como os bancos de dados SQLite podem ser usados para arquivar notícias do Calendário Econômico, de modo que os Expert Advisors montados pelo Wizard possam usá-los para gerar sinais de trade.
Desenvolvendo um EA multimoeda (Parte 11): Início da automação do processo de otimização Desenvolvendo um EA multimoeda (Parte 11): Início da automação do processo de otimização
Para obter um bom EA, precisamos selecionar muitos bons conjuntos de parâmetros para as instâncias das estratégias de trading. Isso pode ser feito manualmente, executando a otimização em diferentes símbolos e, em seguida, escolhendo os melhores resultados. Mas é melhor delegar esse trabalho para um programa e se concentrar em atividades mais produtivas.
Ganhe uma Vantagem sobre Qualquer Mercado (Parte II): Previsão de Indicadores Técnicos Ganhe uma Vantagem sobre Qualquer Mercado (Parte II): Previsão de Indicadores Técnicos
Você sabia que podemos obter mais precisão ao prever certos indicadores técnicos do que ao prever o preço subjacente de um símbolo negociado? Junte-se a nós para explorar como aproveitar essa percepção para melhores estratégias de negociação