トップ  >  自作してみる >  プログラミング未経験者向け  >  F1-4.プログラミングの基礎3(変数配列)
スポンサーリンク
検索

↑の検索エンジンが表示されない人は、
↓の古い検索エンジンを使用して下さい。
カスタム検索
MQL4リファレンスツリー
F1-4.プログラミングの基礎3(変数配列)




プログラムの3つの基本動作「処理」「条件分岐」「繰り返し」について学んだので、
それを駆使してプログラムを作成する事が可能になりました。

ですがMQL4プログラミングを学習する為にはもう少し知っておかなければならない事があります。


変数配列

まずは変数配列についてです、これは以前学んだ変数の応用です。

変数を使用する為には、データ型と変数名を決めて宣言して使える状態にする必要がある事は覚えていますよね?
プログラミング基礎


ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_value;              // int型の変数を宣言

}



ここで同じ使用目的で使用する変数を12個用意する事を考えてみましょう。
使用目的は同じですが、区別する為にラベル名に連番を付けると

プログラミング基礎

こんな感じで12本の容器を用意して、それぞれラベルを用意して個別の名前を付ける事になります。
これをプログラムで書いてみると

ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_value1;              // int型の変数を宣言
    int      template_value2;              // int型の変数を宣言
    int      template_value3;              // int型の変数を宣言
    int      template_value4;              // int型の変数を宣言
    int      template_value5;              // int型の変数を宣言
    int      template_value6;              // int型の変数を宣言
    int      template_value7;              // int型の変数を宣言
    int      template_value8;              // int型の変数を宣言
    int      template_value9;              // int型の変数を宣言
    int      template_value10;             // int型の変数を宣言
    int      template_value11;             // int型の変数を宣言
    int      template_value12;             // int型の変数を宣言
}


凄い無駄な事をやっていると思いません?
まるでIT企業の・・・もう下りは聞き飽きましたよねw

この12個の変数がそれぞれ違う目的で使用されるのであればこの書き方で問題無いのですが、
今回は使用目的が同じ変数を12個宣言するので、こんな手間のかかる事はしません。

仮にこれが1万個必要だったら1万行コピペして全部名前を手作業で変更しますか?コンピュータを使っているのにそんな手作業をするなんて●呆ちゃんですよね? そんな阿●ちゃんが現実のIT企業に沢山いますw
そしてそんな無駄な事を何の疑いも無く手作業でこなして残業をして、「仕事をやった感」で心を満たして残業代を稼ぐ所謂生活残業をする社員が沢山いますが、実は会社にはこういう無駄な作業というのが改善されずに残り続けます。 理由は無能な人の雇用を維持する為に、こういう無意味で謎な何の役にも絶たない業務というのが会社から提供されるからです。

ここで変数配列が出てきます。
配列という言葉自体の意味は分かりますよね?
配列は「並べること。並びぐあい。また、一定の仕方で並べたもの。」という意味なので、変数配列とは変数を並べるという事が想像出来ます。

現実世界でのイメージでは
プログラミング基礎

こんな感じです。
変数配列とは容器を並べるケースのようなもので、ラベルはケースに一つ貼ってあるだけです。
ケースに容器を12本並べて、ケースに「これはビールです」と記載しておけば「このケースの中に入っているのは全部ビールか」と分かりますよね?
スポンサーの関係で他社製品のラベルが見えるとマズイのでラベルを全て剥がしてしまったので、何の飲み物か分からない状態の容器でも、ケースにラベルを張っておけばこれが何の飲み物か理解出来ますよね?

これをプログラムで書くと

ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言
}


こうなります。
単品の変数宣言との違いは分かりましたでしょうか?

プログラミング基礎

変数配列宣言はこのように変数名の後に[]を付ける必要があります。
[]の中は要素数を指定します。要素数というのは配列の長さです。

この要素数を9に変更すれば、配列の長さは9になります。
つまりビール瓶が9本入るケースが用意されるという事です。

ちなみに変数名をtemplate_valueからtemplate_arrayに変更しましたが、
これは単純に変数名から「これは変数配列だ」という事が分かるようにする為です。
「Array」とは配列という意味です。


ところでプログラミング未経験者の人はちゃんと手を動かして説明した通りにプログラムを作成して動作させていますよね?
ただ見ているだけでは全く役に立たないので、面倒でも実際に手を動かして下さい。
MQL未経験者向け


変数配列の初期化

変数配列も変数と同様に初期化をする必要があります。

当然、一つ一つ指定して初期化するわけではありません。
変数配列を初期化するには配列関数というものを使用します。

「配列関数?そりゃなんじゃい?」っと思ったでしょう。詳細は後で説明しますので今は気にしないで下さい。
今はとにかく指示された通りに手を動かしてみて下さい。

それでは 配列関数ArrayInitialize()関数を使って変数配列を初期化しましょう。

「はぁ!?コラ!おいてめぇ~!ArrayInitialize()関数?そんなの聞いた事ねーぞ!このダボ!」
プログラミング基礎


っと思ったでしょう。
言いたい事は分かりますが、 関数についての説明は後でします。
とにかく今は何も考えずに指示された通りに手を動かして下さい。


ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );
}


今やっているのはこんな感じです。
プログラミング基礎

template_arrayのラベルが貼ってあるケースまるごと酒屋さんに渡して、「それ全部洗っておいて(0で初期化しておいて)」とお願いしています。
「そんなもの自分で洗えよ!酒屋さんを何だと思ってるんだ!そもそも酒屋さんはそんな事してくれんわ!」と思うかもしれませんが、例えですので。
ビール瓶を洗う達人にお任せして、ビール瓶を全て洗って貰っている状態です。

ちなみに
ソースコード:
    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );


初期化する配列を渡す時にtemplate_array[]では無く、template_arrayを渡しています。
template_array[]は宣言の時に「template_arrayは配列です」と宣言する為のものであって、使用する時は[]を付けません(詳細は次説明します)。
今回はtemplate_arrayというラベルを貼ったケースを丸ごと酒屋さんに渡しています。
ArrayInitialize()という酒屋さんはケース丸ごとじゃないと仕事を受け付けてくれないからです。

このように変数配列を丸ごと全部渡す時はtemplate_arrayという変数配列名だけを指定します。

これでtemplate_arrayの変数配列の中身は全て0で初期化されました。
未だ中身の確認の説明をしていないので確認出来ませんがw


ところでプログラミング未経験者の人はちゃんと手を動かして説明した通りにプログラムを作成して動作させていますよね?
ただ見ているだけでは全く役に立たないので、面倒でも実際に手を動かして下さい。
MQL未経験者向け



配列要素へのアクセス

配列の特定の要素に対してのアクセス方法を説明します。
どういう事か具体的に説明すると

プログラミング基礎

ビール瓶が並んでいますが、一番左のビール瓶の中身を確認する行為と同じです。
さて問題です、一番左のビール瓶の中身を確認してくるように他人に指示する場合、どのようにして指示するでしょうか?
まぁ人間相手ならそのまま伝えれば良いのですが、コンピュータという機械相手にそんな曖昧な指示は通用しません。

とりあえずプログラムでどうやるのかを見てみましょう。

ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );

    Print( template_array[0] );               // 変数配列の特定要素の値をログ出力

}

これで変数配列の最初の要素の値をログ出力します。


追加したソースコードはこれですが、
    Print( template_array[0] );               // 変数配列の特定要素の値をログ出力


説明をする前に、もう一つ見て欲しい事があります。
今度は2番目の要素に対してアクセスする場合です。
    Print( template_array[1] );               // 変数配列の特定要素の値をログ出力


プログラムが何をやっているのかのイメージは
プログラミング基礎

イメージを見ると感覚的に分かりますよね?


それでは説明に入ります。
プログラミング基礎

変数配列の特定の要素にアクセスする為には、
変数名の後ろに[]を付けて、[]の中に添え字(インデックス)を入れる必要があります。

この添え字(インデックス)というのは、変数配列宣言時の要素数とは異なるので注意が必要です。
個人的にインデックスの方が呼び易いのでインデックスと呼びます。

このインデックスというのは、配列の先頭から幾つオフセットさせるか?という意味を持っています。
例えば2番目の要素にアクセスする時はインデックスは1になりますが、イメージで見てみると
プログラミング基礎

感覚的に分かりましたでしょうか?
オフセットさせる数を指定するので、当然1番目の要素にアクセスする場合はインデックスは0を指定します。
(ちなみにインデックスを0から数え始める事を0オリジン(外部リンク)と呼びます)


オフセット数を指定するという事は最後の12番目の要素へのアクセスする場合、
    Print( template_array[11] );               // 変数配列の特定要素の値をログ出力


プログラミング基礎

インデックスは11になります。


ちなみにインデックスを12(変数配列の範囲外)にした場合。
プログラミング基礎

たまたま隣にあった他人のワインを勝手に飲んでしまう行為と一緒です。
これを現実世界で行うと
プログラミング基礎

泥棒はこうなります。

プログラムでも同様で、たまたま隣にあったデータを勝手に触ってしまう事になります。
コンピュータはプログラムを逮捕する事はありませんが、代わりに「君はルール違反をしたから追放します」という感じでプログラムを強制終了させます。

悪い例を実演してみましょう。
■エラーの悪い例:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );

    Print( template_array[12] );             // ★★★範囲外アクセスエラーのテスト★★★

}


プログラミング基礎

プログラムを実行すると
「array out of range in 'TestProgram.mq4'(16,26)」
と表示されて、プログラムが強制終了されます。
このエラーの意味は「TestProgram.mq4のソースコードの16行目の26列目で、配列の範囲外にアクセスしています。」
という意味です(直訳ではありません)。


これは重要な内容なので絶対に体得して下さい。
ここは初心者や外注SESがデフォルトの様に間違える部分です。
ここでインデックス12を指定してエラーを発生させてしまうと初心者である事がバレバレです。
逆に言えば外注SESがそのエラーを発生させてしまうプログラムを納品したら、
その外注SESの次の契約更新は絶対に止めてください
他社員の工数を無駄に奪い取って足を引っ張るだけの時間泥棒なだけでは無く、最悪会社の信頼を失う事に発展する場合があります。 ITのプロである筈のIT企業の社員でさえ日常的にこの不具合を発生させています (単純に基礎知識不足・単体テストが不十分というか実はテストしていない・拘束時間で給与が貰える為プロである意識が希薄化しているからでしょうが・・・)。

ここで一つ疑問に思った人はいないでしょうか?
「インデックスを0で指定するくらいなら、指定しなくてもいいんじゃないか?」と思いませんでした?
前回説明しましたが、インデックスを付けないで変数配列名だけの場合は、変数配列を丸ごと渡してしまいます。
プログラミング基礎

この謎の酒屋さんに見覚えはありませんか?
そういう事です。


まとめると

プログラミング基礎

変数配列宣言時の[]の中身は要素数(配列の長さ)を指定する。
変数配列の個別要素へのアクセス時の[]の中身は、インデックス(配列の先頭からのオフセット数)を指定する。

「変数配列の宣言時」と「個別要素へのアクセス時」で
同じ[]を使っていますが、意味は異なるので要注意。



ところでプログラミング未経験者の人はちゃんと手を動かして説明した通りにプログラムを作成して動作させていますよね?
ただ見ているだけでは全く役に立たないので、面倒でも実際に手を動かして下さい。
MQL未経験者向け



配列要素の値を変更

それでは実際に変数配列の要素を使ってみましょう。
まずは変数配列の全要素の内容をログ出力するようにして、中身を確認出来るようにします。


ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );

    Print( template_array[0] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[1] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[2] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[3] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[4] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[5] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[6] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[7] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[8] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[9] );               // 変数配列の特定要素の値をログ出力
    Print( template_array[10] );              // 変数配列の特定要素の値をログ出力
    Print( template_array[11] );              // 変数配列の特定要素の値をログ出力

}


まぁこんな外注SESみたいな事をしないで当然forループを使います。

ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );

    for ( int icount = 0; icount < 12; icount++ ) {
        Print( template_array[icount] );               // 変数配列の特定要素の値をログ出力
    }

}


結果:
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0


インデックス指定に変数を用いる事が可能なので、forループのループカウント用変数をインデックスに指定しています。
もし変数配列を使わずに全て個別の変数名を使っていたら、こういう事は出来ません。


配列要素の中身が確認出来るようになったので、配列要素の値を変更してみましょう。

ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );

    template_array[0] = 1;                    // 配列要素に値を代入


    for ( int icount = 0; icount < 12; icount++ ) {
        Print( template_array[icount] );               // 変数配列の特定要素の値をログ出力
    }

}



結果:
TestProgram EURUSD,H1: 1
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0
TestProgram EURUSD,H1: 0


変数配列の先頭の要素に1という値が入りました。


ソースコード:
    template_array[0] = 1;                    // 配列要素に値を代入


やっている事は変数へ値を代入するのと同じです。
変数配列の個別要素を指定した場合、単独の変数のように扱う事が出来ます。



ところでプログラミング未経験者の人はちゃんと手を動かして説明した通りにプログラムを作成して動作させていますよね?
ただ見ているだけでは全く役に立たないので、面倒でも実際に手を動かして下さい。
MQL未経験者向け



範囲外アクセスしない為に、配列サイズを取得する(ArraySize)

先程のサンプルソースは、範囲アクセスに関係するforループ内でハードコーディング(直値)を使用しているので、
実は良いサンプルソースではありません。

ソースコード:
    for ( int icount = 0; icount < 12; icount++ ) {


今は初心者に分かり易いようにあえてハードコーディングを使用していますが、実はこれプログラミング未経験者の外注SESがよくやりがちなソースコードです。
作った時はこれで動作するかもしれませんが、変更が入った時に変更漏れがあって範囲アクセスしてしまう鉄板パターンです。

配列宣言とforループのハードコーディングにdefineマクロを使用する方法もありますが、もっと良い方法があるのでそちらを紹介します。
defineマクロの場合、動的配列に対して使えないからです。
(突然defineマクロという謎用語が出てきましたが、これはあと(EA作成のあたり)で解説します)。

変数配列にアクセスする際に、その変数配列の要素数を取得する関数(ArraySize)を使用します。
forループで直値の12を使用していた箇所をArraySize()関数に置き換え、関数の引数に要素数を知りたい変数配列を指定します。

ソースコード:
    for ( int icount = 0; icount < ArraySize(template_array) ; icount++ ) {




ソースコード全体では以下の通りになります。
ソースコードを未だ見慣れていない初心者の方は、直接数値が指定されていた方が理解し易いかもしれませんが、
いずれはこういうバグを招き難いソースコードの書き方をしなければなりません。

ソースコード:
#property strict // strictは絶対に削除しない事

//+------------------------------------------------------------------+
//| プログラムスタート
//+------------------------------------------------------------------+
void OnStart()
{
    int      template_array[12];              // int型の変数配列を宣言

    // 配列を初期化
    ArrayInitialize(
                    template_array,           // 初期化する配列
                    0                         // 設定する初期値
    );

    template_array[0] = 1;                    // 配列要素に値を代入


    for ( int icount = 0; icount < ArraySize(template_array) ; icount++ ) {
        Print( template_array[icount] );               // 変数配列の特定要素の値をログ出力
    }

}



スポンサーリンク


Copyright ©2015 MT4でEA自作しちゃお~ All Rights Reserved.


Top

inserted by FC2 system