複数の値をまとめて扱う事は、プログラムにおいて多々あります。というか、多数の値をまとめて処理してこそのプログラムとも言えます。一つや二つのデータであれば、一つ一つ個別に変数宣言しても全く問題ありませんが、これが数百、数千、数万となると一つ一つ宣言する事は無理無茶無謀な所業となります。そこで必要となるのが、変数をまとめて宣言して使用できる配列です。今回はこの配列について解説していきます。
--
いきなりここに飛んで来ちゃった人は、よろしければ下記からご覧ください。

  • 配列宣言の基本
配列は複数の変数をまとめて宣言する仕組みです。今まで解説してきた int や float といった型は、全て配列として宣言する事が出来ます。これは変数名の後ろに [] で要素数を指定する事で宣言します。例えば、100 個の int を扱いたい場合は

int sample[100];

このような宣言を行う事で、100個の int型をまとめて宣言する事が出来ます。宣言可能な数ですが、正直私もよく分かっていないです。おそらく、メモリの許す限りは大きな宣言が出来るのではないでしょうか。システムによっては、実際に値を格納するまでメモリを確保しないかもしれません。言い換えると迂闊に巨大な配列を宣言すると、容易にシステムのメモリを消費します。これを利用したハッキングもよくあったりします。

さて、宣言をしたら、今度は実際に値を格納して使ってみます。先ほど sample という配列を要素数 100 で宣言しました。通常は = で代入等をすれば良いのですが、配列の場合はどの場所に入れるかを指定する必要があります。それが添え字です。あるいはインデックスとも言います。添え字は 0 から始まり、最大要素数 - 1 までが有効範囲です。例えば、100 全てを 0 でクリアしようと思ったら…

for (int i = 0; i < 100; ++i) { sample[i] = 0; }

このように記述する事で 100 の配列全てが 0 で初期化されます。

※ HDMI キャプチャです。これ、意外? な使い方としてはデバッグです。バグは意図せずいきなり発生しますが、キャプチャしておけば巻き戻してどう操作したら起きたかとか、どの場面で起きたかが見えるようになります。コマ送りでバグが発生する瞬間が見えるかも。是非導入をご検討ください。


  • 配列の初期化
配列はメモリの確保と同じです。要素数分の変数を保存するメモリが確保されます。では、何も値を入れていない宣言直後の初期状態はどうなっているか分かりますでしょうか?初期化されていないのですから、メモリの状態によって読み出される値が変わります。少しテストしてみます。

int sample[100]; for (int i = 0; i < 100; ++i) { printf("%x, ", sample[i]); } printf("\n");
書式文字列に新しく "%x" が出てきました。これは数値を 16進数で表示しなさいという指定となります。これを実行してみます。すると…
Debug実行時はCCCCCCCCで初期化されている
全部 cccccccc と表示されました。実は VS2022 では、ステップトレースなどが出来るデバッグ実行では、変数は事前に cccccccc と自動的に初期化されていたりします。これはかなり昔から 0xCC 系統で初期化するという伝統みたいなモノです。今は 32bitのサイズで int は扱われているのがこれで分かりますね。

このデバッグが出来る状態はデバッグビルドと言います。この状態で一般に公開する事は禁じられています。公開するためには、リリースビルドに切り替える必要があります。このプルダウンで、表示を Debug から Release に切り替えてください。
リリースビルドに切り替える
この状態で、[F10] によるステップトレースを試みようとしても、ループがトレースされずそのまま下に抜けてしまいます。ブレークを掛けても止まる事は止まりますが、変数の状態を確認する事は出来ません。そして、変数の自動初期化もありませんので、上記のプログラムを実行すると
Release実行だとよく分からない数値が表示される
このようにバラバラの数値が表示されてしまいます。
※ チェックが終わったら、また Debug に戻してください。

このような不定の値を利用するプログラムを組んではいけません。理由は予測できないためです。バラバラの値を期待していたら、環境によっては 0,0,0 とゼロばかり続くかもしれません。逆に 0 で最初から初期化されていると思い込んでると違ってたりします。初期化されていない変数は無保証です。その無保証を使用した時点で、そのプログラム全体が無保証になると思ってください。
※ 6TBで1万円とちょっと。やっと少し安くなりました!

  • 配列の危険性
配列はとても便利なのですが、C言語においては実行速度を優先しているためか、安全面を考慮されていない部分が多いのです。先に添え字は 0 ~ 要素数 - 1 までだと説明しました。では、これを外して使うとビルドが通らない…のではなくて通ってしまいます。それどころか実行まで出来てしまいます。例えば

int sample[100]; for (int i = 0; i <= 100; ++i) { sample[i] = rand() % 10 + 1; printf("%2d, ", sample[i]); } printf("\n");
プログラムを少し書き換えました。ループの < が <= に変わっています。これでループは 0 ~ 100 までに変わります。配列は 100個なので使用可能な添え字を超えてます。最新のコンパイル環境である VS2022 では、ちゃんと警告を表示してくれます。
警告
この警告表示をダブルクリックすると、問題の場所にカーソルが移動しますので、それを修正すれば直ります。このような単純な問題であれば、VS2022 は自動で検証して問題を指摘してくれます(これを静的解析と呼びます)。ですが、計算結果が予測できない場合で、その計算で添え字を指定しているような場合は、警告の指摘はないかもしれません。そして、これはエラーでは無くて警告なのでそのまま実行できてしまいます。特に Release にしていると、一見全く何も問題なく動作してしまいます。
101個の数値が一見全く問題なく表示される
マイナスの値は使えません…はずが、なんとこれすらもコンパイルは通りますし、実行も出来てしまいます。一見、全く問題なく動きますが、これ、システムが用意していないメモリを勝手に使っている状態です。この異常はメモリへの不正なアクセスと言います。不正アクセス状態では、仮に正常に動いているとしても、それはたまたま動いているだけになります。関係ない変数の値が勝手に変わったり、場合によってはシステム全体がクラッシュする事すらあります。

配列は便利ですが、メモリアクセスに直結している動作ですので、その扱いにはかなり気を配るようにしてください。
シリコンパワー USBメモリ 256GB USB3.2 (USB3.1/3.0/2.0互換) ヘアライン仕上げ Blaze B02 SP256GBUF3B02V1K
シリコンパワー
2019-11-01
※ データの持ち運びには断然こちら。私の現在の主力USBメモリです。値段もかなりこなれています。