配列など

配列とは?

これまでは、データをひとつ扱うためにひとつの変数を宣言してきました。そもそも、コンピュータの日本語訳が「計算機」であることからもわかるように、コンピュータは数値計算を行うために開発されたものです。しかしながら、今日ではコンピュータは数値計算のためというよりは、むしろ大量の情報を高速に処理するための道具として用いられているのが現状です。ところが、「大量の情報」を扱いたいのに、数値 1 個を扱うためにプログラムのコード内で変数 1 個ずつを宣言していたのでは話になりません。そこで用いられるのが「配列」と呼ばれるものです。これは、ひとつの名前を持つ変数に複数個のデータを割り当てる、というものです。変数の名前はひとつなので、その変数が持つ複数のデータを個々に識別するために「添字 (そえじ)」と呼ばれる整数の番号を使います。

配列の使い方

配列の宣言は、普通の変数の宣言とほとんど同じですが、次のように変数名の右側に割り当てるデータの個数を大カッコ [ ] で囲って書きます。

型名 配列名[配列サイズ];

配列サイズは定数でなければなりません。ここで言う「定数」とは、コンパイルの段階でその値がわかっている、ということを指します。また、配列サイズは 1 以上の整数でなければなりません。配列の中の個々のデータ (要素といいます) にアクセスするためには、配列名の右側に添え字を大カッコ [ ] で囲んで書きます。配列の添え字は 0 から始まります。例えば、配列を 3 個確保したとすると、添え字は 0, 1, 2 までが使えます。3 番は 4 個目の値になるので確保した数より多いため、使えません。このように、添え字の最大値は配列サイズより 1 小さくなるので気を付けてください。確保した範囲より外の添え字を参照しようとすると、アクセスバイオレーションになり最悪強制終了されます。では、配列を使ったスクリプトの例を見てみましょう。

配列の使用例

void main(){
    const int len = 100;    //  配列サイズ (定数) を宣言
    int array[len], id, i;  //  配列と作業用変数を宣言
    string test;  //  番号入力用文字列変数
    for(i = 0; i<len; i++) array[i] = i*i;  //  2 乗の値を計算する
    //  数値の入力を求め、キャンセルされたら終了
    if(!InputString("番号を入力してください。", &test)) return;
    id = (int)test;  //  入力された文字列を数値に変換 (キャスト)
    //  添え字が範囲外なら終了
    if(id<0 || len<=id) SysDialog("番号が不正です!");
    //  配列の要素を表示
    else SysDialog(""+id+" の 2 乗は "+array[id]+" です。");
}

定数を使う

このサンプルは、今までやってきたことはもちろん、新しい内容もたくさん入った応用的なプログラムです。がんばって見ていきましょう。まず、配列 array を宣言したいのですが、ここでそのままサイズの数値を書いてしまうと、他の場所でその配列のサイズを使いたいときにもまた同じ値を書かねばならず、後でサイズを変更したい場合などにそれらをすべて直す必要があり大変不便です。しかし、配列のサイズは定数でなければならないので、変数にサイズを入れておいて使うことはできません。そこで登場するのが定数の宣言です。定数は変数とほとんど同じ方法で宣言、初期化できますが、型名の前に const というキーワードを書くところだけが違います。もちろん、定数に後から値を代入することはできませんので、宣言時に必ず初期化 (値の代入) をしなければなりません。このように宣言した定数は、代入したりアドレスを取ったりできない以外は普通の変数と全く同じように使え、さらに配列のサイズとして使うことができます。これで、後で配列サイズを変更したいとなってもこの 1 箇所だけを変えればいいことになりますので楽ですね。

for ループと配列

for ステートメントはよく配列と一緒に使用されます。配列の各要素を順に処理したい場合に、for を使えばカウンタの初期化やインクリメントが簡単に行えるからです。このサンプルの例では、配列 array の i 番目の要素に i の 2 乗の値を代入しています。for のカウンタ i は 0 から始まり、条件式は i<len となっていることに注意してください。配列サイズが len ですから、使える添え字は len-1 までなので、条件を i<len のようにする必要があるのです。

文字列を入力する

これまで SysDialog 関数などでメッセージをユーザーに表示することは行ってきましたが、逆にユーザーから入力を受け付けることは、YesNoDialog で 0 か 1 かのデジタル値を受け取るだけでした。そこで、InputString 関数を用いてユーザーに任意の文字列を入力させる方法を説明します。

int InputString(string label, string *ret);

InputString 関数のプロトタイプは上のようになっています。第 1 引数 label は、入力ボックスと共に表示するメッセージを渡します。第 2 引数 ret は、入力された文字列を代入するための string 型変数のアドレスを渡します。「OK」が押されると 1 が、「キャンセル」が押されると 0 が戻り値として返されます。ですので、0 が返されたときに return してプログラムを終了するようにしています (このように、条件反転演算子 ! はよく使うのでしっかり理解しておいてくださいね)。

データ型の変換・キャスト

次に、入力された文字列を添字として使いたいので整数に変換する必要があります。しかし、string 型変数に数値を代入すると自動的に数値が文字列に変換されるのに対し、int などの数値型変数に文字列を代入しようとしても自動的には変換を行ってくれません。このような場合に、変数の型を強制的に変換する方法として「キャスト」があります。キャストは、変換したい変数 (あるいはカッコで囲まれた数式) の左側に、変換したい型名をカッコで囲んで付加します。ですから、この場合は (int)test となりますね。文字列型を数値に変換する場合は、システムが文字列を一文字一文字調べ、可能な限り数値としての情報を取り出そうとします。しかし、アルファベットや平仮名、漢字など数字以外の文字が入っていると、読み取れないので 0 として変換します。実は、文字列型に数値を代入する場合も、暗黙的にキャストは行われているのです。しかし、文字列を数値に変換するとなると情報量の欠落が大きいため、プログラマが明示的にキャストを指示しない限り変換は行われないのです。このようにして、見事ユーザーから数値を入力させることに成功しました。

エラーチェックと配列参照

ユーザーから数値を入力してもらうことには成功しましたが、その数値が必ずしも配列として使える添え字の範囲内にあるとは限りません。このため、データの精度が不確定な数値を添え字に使う場合は、不正アクセスを避けるために数値の範囲を調べなければなりません。この場合は、数値 id が負であるか、または len 以上であれば使用可能な添字の範囲から外れることになります。このように、「または」であるとか「かつ」というように、複数の条件を結合するための演算子に論理演算子 || と && があります。|| は、両方のオペランドが偽であれば 0 を返し、それ以外であれば 1 を返します。つまり、「または」ですね。一方 && は、両方のオペランドが真であれば 1 を返し、それ以外であれば 0 を返します。こちらは「かつ」ですね。論理演算子のすばらしいところは、余分な評価を行わない点にあります。例えば、|| はどちらかでも真なら 1 を返すことが決定しますので、左側のオペランドが真ならば右側のオペランドは評価されません。&& はどちらかでも偽なら 0 を返すことが決定しますので、左側のオペランドが偽なら右側のオペランドは評価されません。プログラム上の余分な (余分≠無駄) 処理をオーバーヘッドといい、論理演算子はオーバーヘッドを軽減するためのひとつのアプローチになります。こうして添え字が無効な値ならエラーメッセージを表示し、正しい値なら配列の該当する要素を読み取って表示します。

まとめ

今回のレッスンは本題とは関係ない項目のほうが多かったですね;しかし、できるだけ短期間で基礎をマスターしていただくためには、このように複数の内容を同時に紹介していくほうが効率的かと思いますのでご了承ください。本題の配列も、C 言語の中ではとっても重要な内容なので (Queek II で RPG を作る上ではあまり使わないかもしれませんが) ぜひ理解してください。

配列とは無関係の演習問題

積和演算子 * と + の優先順位のように、論理演算子 && は、|| より高い演算順位を持つ。次のプログラムの実行後、各変数の値はどのようになるか。また、なぜそうなるか考察せよ。

int a = 0, b = 0, c = 0;
if((b = 1) || (a = 2) && (c = 3)) b = c;

<PrevPage | ▲SecTop | ▲PageTop | NextPage>
Copyright (c) 1999-2006 インターネット停留所