4.配列変数

 大量のデータを処理するための「簡単なプログラムの作成」の章では、プログラムを作って、コンピュータを電卓替わりに使えることを覚えました。そこでの知識に加えて、ここで説明する「制御構造」を覚えれば、電卓には出来ないような大量の計算を実行させることが出来るようになります。
 4.1 配列変数を理解するために
 先に「流れ制御」の話をしましたが,その最も基本的な使い方の一つは配列変数と組み合わせ、簡潔な記述で大量のデータを処理することです。配列変数という概念も、プログラミングのもっとも基本的な概念の1つです。先へ進む前に、配列変数とは何かについて説明します。
 たとえば、100人の学生の試験の採点結果があったとしましょう。試験を実施した教師は、平均点や最高点、最低点を調べたり、下駄を履かせたり、成績を判定したりしなくてはなりません。そのような処理をするのに自分でプログラムを作成して、コンピュータで処理することにしたとしましょう。
 この講座の「簡単なプログラムの作成」程度の知識でも、そのようなプログラムを作成することは、原理的には可能です。多分その程度の知識だと次のようなプログラムを作成することとになるでしょう。


 プログラム例 4.1.1
  #include <stdio.h>
  void main(void){
     /* 点数を記憶する変数を100人分宣言し、宣言と同時に点数を代入する*/
     int tensu_001=75;
     int tensu_002=65;
     int tensu_003=80;
         ...
     int tensu_099=60;
     int tensu_100=90;
     int saiko, saitei; /*最高点と最低点を記憶する変数の宣言*/
     int goukei;        /*合計点を記憶する変数の宣言*/
     float heikin;      /*平均点を記憶する変数を宣言*/

    /*平均点をもとめるには、合計点をもとめたあと、100で割ることとします*/
    /*合計点をもとめる。100行必要ですね */
     goukei = tensu_001;
     goukei = goukei + tensu_002;
     goukei = goukei + tensu_003;
     goukei = goukei + tensu_004;
              ...
     goukei = goukei + tensu_099;
     goukei = goukei + tensu_100;
     /*平均点をもとめる */
     heikin=(float)goukei/100.;  /*小数部が切り捨てにならないよう(float)で型変換*/
  }


 単純な式を100人分書かなければなりません。とても、大変で、うんざりしますよね。そこで、このような問題を解決するために配列変数という考え方が登場します。

 でも、このプログラムにも学ぶべきところがあります。合計点の求め方ですね。おもしろいと思いませんか。多分、みなさんは、次のような書き方を思い付いたのではないでしょうか
  goukei = tensu_001 + tesu_002 + tesu_003 + ... + tensu_099 + tensu_100

 4.2 配列変数と配列要素、配列サイズ
 では、ここで、配列変数に登場してもらいましょう。説明を読む前に次のプログラムを自分なりに理解してみて下さい!

 プログラム例 4.2.1  実行結果
  #include <stdio.h>
  void main(void){
     /*サイズ5の整数型配列変数の宣言*/
     int tensu[5];

     /*5個の配列要素へ点数を代入 */
     tensu[0]=75;
     tensu[1]=80;
     tensu[2]=60;
     tensu[3]=90;
     tensu[4]=85;

     /*5個の配列要素を表示 */
     printf("tensu[0]=%d\n",tensu[0]);
     printf("tensu[1]=%d\n",tensu[1]);
     printf("tensu[2]=%d\n",tensu[2]);
     printf("tensu[3]=%d\n",tensu[3]);
     printf("tensu[4]=%d\n",tensu[4]);
  }
  tensu[0]=75
  tensu[1]=80
  tensu[2]=60
  tensu[3]=90
  tensu[4]=85


 配列変数は、内容的に同一のグループに分類される多量のデータを同じ名前の変数で扱えるようにするものです。配列変数も通常の変数と同様、型を指定して変数宣言をします。プログラム中の先頭の
 int tensu[5];
の宣言文が文が配列変数の宣言文です。
 ただし、通常の変数宣言と違って、配列変数名tensuの後ろに[5]と記されています。これは、配列変数tensuのサイズとよばれ、5個の整数型変数が納まるように変数の領域を確保しますという意味です。配列変数名とは,この領域の名前だと考えてください.
 ことばでは、わかりにくいので、図を使って説明しましょう。次の図は、メモリー中に、配列変数tensuの領域が整数型変数5個分確保され、更にデータが代入された後の様子を示しています。配列変数名tensuは、tensu[0]からtensu[4]までの領域に付けられる名前です。tensu[0]、tensu[1]、tensu[2]、tensu[3]、tensu[4]のことを配列要素とよびます。配列要素の[ ]中の数字は配列の添字と呼ばれ、個々の要素を指定するのにつかわれます。上のプログムをもう一度見て下さい。個々の要素にデータを代入するときや、要素を表示するとき添字で指定しているのがわかります。添字は0から始まることに注意してください。


  メモリー
 
 
 要素 tensu[0]    75
 要素 tensu[1]    80
 要素 tensu[2]    60
 要素 tensu[3]    90
 要素 tensu[4]    85





 4.3 配列要素の指定のしかた
 配列要素は、変数や式で指定できる. 前のプログラムでは、配列要素を指定するとき、0,1,2,..などの定数を使っていますが、式で指定することもできます。次のプログラムはそのことを示します。
式とは i, i+1, 2*i+5,i*i....などの表現のことです.i のようにただの変数1個だけでも式とよぶことに注意!
 
 プログラム例 4.3.1  実行結果
  #include <stdio.h>
  void main(void){
     /*サイズ5の整数型配列変数の宣言*/
     int tensu[5];
     int i;

     /*5個の配列要素へ点数を代入 */
     tensu[0]=75;
     tensu[1]=80;
     tensu[2]=60;
     tensu[3]=90;
     tensu[4]=85;

     /*5個の配列要素を表示 */
     i = 0;
     printf("tensu[%d]=%d\n", i, tensu[i]);
     i++;
     printf("tensu[%d]=%d\n", i, tensu[i]);
     i++;
     printf("tensu[%d]=%d\n", i, tensu[i]);
     i++;
     printf("tensu[%d]=%d\n", i, tensu[i]);
     i++;
     printf("tensu[%d]=%d\n", i, tensu[i]);
  }
  tensu[0]=75
  tensu[1]=80
  tensu[2]=60
  tensu[3]=90
  tensu[4]=85


 4.4 for(),while()と配列変数
 配列要素が式で指定することができることを利用すれば,先のプログラムは,for文やwhile文と組み合わせて,次のように書き変えることができる.

 プログラム例 4.4.1  実行結果
  #include <stdio.h>
  void main(void){
     /*サイズ5の整数型配列変数の宣言*/
     int tensu[5];
     int i;

     /*5個の配列要素へ点数を代入 */
     tensu[0]=75;
     tensu[1]=80;
     tensu[2]=60;
     tensu[3]=90;
     tensu[4]=85;

     /*5個の配列要素を表示 */
     for(i = 0; i<5; i++){
         printf("tensu[%d]=%d\n", i, tensu[i]);
     }
  }
  tensu[0]=75
  tensu[1]=80
  tensu[2]=60
  tensu[3]=90
  tensu[4]=85



 4.5 配列変数を宣言時に初期化する
 他の変数と同様,配列変数も,宣言時に初期化することができます.
方法としては,プログラム例4.5.1に示す方法とプログラム例4.5.2に示す方法の二通りの方法があります.

プログラム例4.5.1は,特別説明する必要もないかと思いますが,
    int tensu[5] = { 75, 80, 60, 90, 85};
と書けば,{ }にならべた順序に要素tensu[0]からtensu[4]に数値が代入されます.


 プログラム例 4.5.1  実行結果
  #include <stdio.h>
  void main(void){
     /*配列変数を宣言時に初期化する*/
     int tensu[5] = { 75, 80, 60, 90, 85};
     int i;

     /*5個の配列要素を表示 */
     for(i = 0; i<5; i++){
         printf("tensu[%d]=%d\n", i, tensu[i]);
     }
  }
  tensu[0]=75
  tensu[1]=80
  tensu[2]=60
  tensu[3]=90
  tensu[4]=85



2つ目の初期化の方法を,プログラム例4.5.2に示します.
   int tensu[ ] = { 75, 80, 60, 90, 85};
初期化の方法と言うより配列変数の宣言のしかたということになるかもしれませんが,配列の初期値を宣言時に明示すれば,サイズ(要素数)を明示しなくとも,初期値の数だけ配列要素が準備されます.

 プログラム例 4.5.1  実行結果
  #include <stdio.h>
  void main(void){
     /*配列変数を宣言時に初期化する*/
     int tensu[ ] = { 75, 80, 60, 90, 85};
     int i;

     /*5個の配列要素を表示 */
     for(i = 0; i<5; i++){
         printf("tensu[%d]=%d\n", i, tensu[i]);
     }
  }
  tensu[0]=75
  tensu[1]=80
  tensu[2]=60
  tensu[3]=90
  tensu[4]=85



 4.6 合計(総和)や平均値を求める.
 プログラムで合計点や平均値を求める手順(アルゴリズム)は,C言語に限らずどのような言語でも必ず必要となる最も 基本的な処理です.ここでは,この章の最初に話したプログラムを配列変数を使って書き換えてみました.
簡単な説明ですが,大切なアルゴリズムなので良く理解してください.


 プログラム例 4.6.1  実行結果
#include <stdio.h>
void main(void){
  int n = 10;
  int tensu[10]={ 75, 80, 60, 90, 85,
                  35, 95, 70, 50,100};
  int gokei;
  double heikin;
  int i;

  gokei = 0;/* 1)点数を加算する前に0と初期化 */
  for(i = 0; i < n; i++){
    gokei += tensu[i];
  }
  heikin = (double)gokei / (double)n;
  printf("合計点:%d\n", gokei);
  printf("平均点:%7.2f\n", heikin);
}
 合計点:740
 平均点:  74.00
  



 4.7 多数のデータから最大値や最小値を見つける.
 流れ制御文と配列変数の知識があれば,プログラムを作成して,いろんな処理が出来るようになります.前述の平均値を求めるプログラムもそのひとつです.
今度は,多数の数値から,最大値や最小値を見つける手順(アルゴリズム)を紹介しましょう

 まずは,配列に記憶された点数の中から,最高点を見つけるアルゴリズムです.
最大値を記憶させる変数 max を用意します.
仮に, 0 番目の配列要素 tensu[0] を仮の最大値と置きます.
   max=tensu[0]:
の行がそうですね.
プログラムの説明を簡単にするため,次のようにことばで書いてみました.
ここで,各行の先頭の■が制御文,●が実行文のつもりです.
      ●要素0の記憶内容を仮に最大値maxとする.
   ■for(要素番号1から9までについて){
      ■if(配列要素の値がmaxより大きければ){
         ●maxに記憶されている値を,見つかった要素の値と入れ替える.
             }
       }
     ●最大値をプリントする


 プログラム例 4.7.1  実行結果
#include <stdio.h>
void main(void){
  int n = 10;
  int tensu[10]={ 75, 80, 60, 90, 85,
                  35, 95, 70, 50,100};
  int max;
  int i;

  max = tensu[0];
  for(i = 1; i < n; i++){
      if( max < tensu[i]){
          max = tensu[i];
      }
  }
  printf("最高点:%d\n", max);
}
最高点:100
  


 次に最小値を見つけるプログラムです.いまの場合,試験点数を処理していますから最低点ということになりますね.
最大値をみつけるプログラムを参考に理解を試みてください.

 プログラム例 4.7.1  実行結果
#include <stdio.h>
void main(void){
  int n = 10;
  int tensu[10]={ 75, 80, 60, 90, 85,
                  35, 95, 70, 50,100};
  int min;
  int i;

  min = tensu[0];
  for(i = 1; i < n; i++){
      if( min > tensu[i]){
          min = tensu[i];
      }
  }
  printf("最低点:%d\n", min);
}
最低点:35
  



 4.8 もちろん,配列変数はいくつでもつかえます
 他の変数と同様,配列変数もプログラム中でいくつでも使うことができます.
次の例は,10人の学生の英語(配列eng)と数学(配列math)の試験結果を整理して,それぞれの学生の2科目の平均点(ave)を求めます.もちろん,それぞれの配列で,各要素に点数を代入するときは,学生の番号順に並べる必要があります.たとえば,eng[3]とmath[3],ave[3]は同じ学生の点数でなくてはややこしいということです.
 気をつけなければならないのは,個々の科目の点数は整数値でも,平均点は実数値になる可能性があることです.したがって,平均点を代入する配列は実数型変数を使います.


 プログラム例 4.8.1  実行結果
#include <stdio.h>
void main(void){
  int n = 10;
  int eng[10] =  { 75, 80, 60, 90, 85,
                   35, 95, 70, 50,100};
  int math[10] = { 65, 30, 55, 80, 75,
                   90, 70, 95, 60,65};
  float ave[10];
  int i;

  printf(" no.    eng    math    ave\n");
  for(i = 0; i < n; i++){
    ave[i] = (float)(eng[i] + math[i]) / 2.0;
    printf("%3d %7d %7d %7.2f\n",i+1,eng[i],math[i],ave[i]);
  }
}
 no.    eng    math    ave
  1      75      65   70.00
  2      80      30   55.00
  3      60      55   57.50
  4      90      80   85.00
  5      85      75   80.00
  6      35      90   62.50
  7      95      70   82.50
  8      70      95   82.50
  9      50      60   55.00
 10     100      65   82.50