配列

    2012/06/11

    本章では下記の内容を学習します。

    • 一続きのデータを作る: 配列
    • データをまとめて入力する: 配列の操作
    • データをまとめて初期化する: 配列の初期化
    • データの次元数を増やす: 二次元配列

    配列

    配列の宣言と操作

    例1-収支表の作成
    #include <stdio.h>
    
    int     main( void )
    {
      // 例1: 収支表の作成
      int     shuushi[2];
    
      // 収支表配列に、収支を入れる
      shuushi[0]  = 5000;
      shuushi[1]  = -10000;
    
      // 収支表配列から、収支を取り出す
      printf( "1日目の収支: %d\n", shuushi[0] );
      printf( "2日目の収支: %d\n", shuushi[1] );
    
      return  0;
    }
    

    前回までにたくさんの変数を利用してきました。これら変数には、1 つの変数につき 1 つの情報のみを記憶できるとお伝えしました。ですが、複数の情報を一度に覚えておきたい場合、とくに一続きのデータを連結して覚えておきたい場合などは、変数をたくさん用意しなければならず、大変なことになってしまいます。これを解決できる機構として、配列があります。

    配列は、一続きのデータを連結して覚えておくことができる変数です。配列を利用すると、1 つの変数に対して、複数個のデータを格納することができるようになります。

    配列は、変数名の後ろに [ ] という大カッコをつけて宣言します。この大カッコの中に、覚えておきたい数を記述すると、それだけの値を覚えておくことのできる変数の領域が一括で取得することができるようになります。この数のことを要素数と呼びます。例では、2 日分の収支表を作成しています。2 日分のデータを覚えるために、int shuushi[2]; という int 型の配列を作成し、その要素数を 2 としています。

    配列にデータを格納するときは、変数名[要素番号] = 値; といった具合に、変数名と番号を指定します。番号は 0 から数えはじめますから注意してください。プログラムでは何でもスタートは 0 番からです

    配列からデータを取り出す場合も、変数名[要素番号] という形で指定すれば、その位置に格納されている値を取り出すことができます。例では printf 関数でそれを行っています。

    練習問題: 収支を増やす
    1. 収支表を 4 日分に増やし、3 日目は-20000、4 日目は+35000 にしてください
    2. それを表示して確かめてください

    配列と for 文

    例2-for文を使った収支表の一括表示
    #include <stdio.h>
    
    int     main( void )
    {
      // 例2: for文を使った収支表の一括表示
      int     shuushi[4];
    
      // 収支表配列に、収支を入れる
      shuushi[0]  = 5000;
      shuushi[1]  = -10000;
      shuushi[2]  = -20000;
      shuushi[3]  = 35000;
    
      // 収支表配列から、収支を取り出す
      for( int i=0; i<4; i++ )
      {
          printf( "%d日目の収支: %d\n", i+1, shuushi[i] );
      }
    
      return  0;
    }
    

    前回の例では、変数名は 1 つになりましたが、これだけでは変数を 2 個用意するのと、あまり差がありません。配列が最も威力を発揮するのは、一続きのデータを一括で処理するときです。

    配列はfor文で処理を行うと、カウンタ変数を通して、一括処理が可能になります。例では 4 日分の収支配列が、for 文によって 1 行で表示されています。

    配列の要素番号部分には、変数を利用することができます。これによって、繰り返し構文を利用した一括処理が実現できます。このように配列と繰り返し構文は、とても高い親和性があります。配列を利用するシーンの多くは、繰り返し構文のなかであるとも言えますね。

    練習問題: 収支を統計演算
    1. 4 日分の収支の、平均値を計算してください
    2. 4 日分の収支の、最大値を計算してください

    配列への入力

    例3-収支表の一括入力
    #include <stdio.h>
    
    int main( void )
    {
      // 例 3: 収支表の一括入力
      int shuushi[4];
    
      // 収支表配列に、収支を入れる
      for( int i=0; i<4; i++ )
      {
          printf( "%d日目の収支: ", i+1 );
          scanf_s( "%d", &shuushi[i] );
      }
    
      printf( "-----------------------\n" );
    
      // 収支表配列から、収支を取り出す
      for( int i=0; i<4; i++ )
      {
          printf( "%d日目の収支: %d\n", i+1, shuushi[i] );
      }
    
      return  0;
    }
    

    配列へ決まった値を入れるのではなく、ユーザから入力してもらいたい場合は、scanf_s 関数を利用することになります。配列に対して scanf_s 関数を実行する場合は、&配列名[要素番号] と配列に対して & を記述すれば、配列へデータを入力してもらうことができるようになります。

    練習問題: 入力した収支を統計演算
    1. 入力した結果に対して、平均値と最大値を表示できるようにしてください
    2. 7 日分の入力ができるようにしてください
    応用問題: 入力を打ち切る
    1. 7 日分の配列を作っておきますが、ユーザが『-99999』と入力した場合は、そこで入力を打ち切ったとみなして、入力を中断してください
    2. 平均値・最大値の計算を、打ち切り前の分で計算できるようにしてください

    配列の初期化

    配列の初期化

    例4-配列の初期化
    #include <stdio.h>
    
    int main( void )
    {
      // 例 4: 配列の初期化
      int shuushi[4] = { 5000, -10000, -20000, 45000 };
    
      // 収支表配列から、収支を取り出す
      for( int i=0; i<4; i++ )
      {
          printf( "%d日目の収支: %d\n", i+1, shuushi[i] );
      }
    
      return  0;
    }
    

    変数の初期化は、変数の宣言時に同時に行うことができました。配列の場合は初期化をしたい場合は複数の要素を指定しなければならなくなりますが、このような指定はできるのでしょうか?

    配列変数の初期化には、{ } を利用します。中カッコのなかに、配列の要素数分までの値を、カンマ区切りで指定すれば、配列の宣言と初期化を一度に行うことができます。例では、4 日分の配列変数を用意し、それに対して 4 日分の初期値を { } を利用して与えています。

    要素数を指定しない初期化

    例5-要素数を指定しない、配列の初期化
    // 例 5: 要素数を指定しない、配列の初期化
    int shuushi[] = { 5000, -10000, -20000, 45000 };
    

    配列変数は、要素数を指定しないで初期化することができます。この場合、要素数は中カッコで指定された初期値の数と同じになります。一種の省略記法です。

    練習問題: 払出枚数の配列
    1. 払出枚数を配列として記憶することを考えます。要素数 10 の配列 table_harai[10] を作成して、7 が 15 枚、8 が 8 枚、9 が 1 枚、0,1 が 3 枚、残りは 0 枚、という情報を覚えさせてください
    2. 前回の課題から、initChuusen 関数と、getChuusen 関数を移植し、抽せん結果を元に、払出枚数を配列を利用して決定し、表示してください
    応用問題: 機械割シミュレータ
    1. 練習問題を利用して、機械割シミュレータを作成します。入力された回数分だけ抽せんを繰り返し、払出枚数の合計を表示するプログラムを作成してください
    2. OUT / IN を計算し、機械割を表示できるようにしてください
    3. 機械割が 94%前後になるように調整してみてください
    4. 機械割が 118%前後になるように調整してみてください

    二次元配列

    例6-二次元配列
    #include <stdio.h>
    
    int main( void )
    {
      // 例 6: 二次元配列
      int shuushi[12][31];
    
      // 二次元配列への代入
      shuushi[0][0]   = 10000;
      shuushi[1][2]   = -5000;
      shuushi[3][28]  = 20000;
    
      // 二次元配列から値を取り出す
      printf( "1月1日の収支は%d\n", shuushi[0][0] );
      printf( "2月3日の収支は%d\n", shuushi[1][2] );
      printf( "4月29日の収支は%d\n", shuushi[3][28] );
    
      return  0;
    }
    

    配列は一連のデータを覚えておくのに便利ですが、このデータが二次元的に展開されるようなものの場合、それに対して配列を適用することができるのでしょうか?

    配列は二次元以上に拡張することができます。例では 1 年分の収支表を作成しています。31 日分の配列を 12 月分確保する必要がありますから、2 つの次元が必要になっています。

    二次元配列の利用は、基本的に一次元配列の要素に、2 つ目の要素が追加された形になります。それさえ気をつければ、特に注意すべき点はありません。

    なお、配列は二次元どころか、三次元でも四次元でも作成することができます。ただし実用範囲といえるのは三次元までで、四次元ともなると、要素数が爆発的に増加してしまいます。各次元が 100 の要素を持つ四次元配列の場合、100×100×100×100 個で 1 億個の配列要素が必要になりますから、これは実用的とは言えないでしょう。

    練習問題: 年単位収支表の作成
    1. 年単位収支表の要素を、すべて-99999 で埋めてください(これは初期化指定子 { } でやるのは現実的ではありません、for 文で行いましょう)
    2. 1/1、2/3、4/29 の要素をプログラムで指定してください(例題と同じで OK です)
    3. 『収支額が-99999 でない日のみ』を表示してください。(for 文をネストして利用する必要があるでしょう)
    応用問題: 年単位収支表を入力できるようにする
    1. 指定した月/日の収支表に、指定した収支額を入力できるようにします。月/日を入力してもらい、その後収支額を入力してもらうと、対象要素に収支額が格納されるようにしてください
      月:3
      日:21
      収支:25000
    2. 上記の入力処理を無限ループで繰り返すものとし、月/日、または収支額のいずれかに-99999 が入力された場合、そこで入力を打ち切れるようにしてください。入力が終わったら、『収支額が-99999 でない日のみ』を表示してください
    応用問題: 年単位収支表の入力制限
    1. 上記の収支表には、2/31 のような、あり得ない日付にも入力ができてしまいます。そこで、そのようなあり得ない日付で合った場合は、再入力を促すようにしてください。(あり得ない日付を判断する方法はいくつかありますが、最も単純な方法は、『その月が何日まであるか配列』を作ることです)
    2. 収支表の平均値、最大値を表示できるようにしてください