配列変数

配列とは

今までの変数の使い方では、10個の変数が必要な時はたとえば

int a0,a1,a2,a3,a4,a5,a6,a7,a8,a9;

と宣言することになります。これは面倒です。そこで

int a[10];

と宣言することにしました。これが配列変数です。

a0,a1,...とa[]との対応は、

a0  a[0];
a1  a[1];
a2  a[2];
a3  a[3];
 ......
a9  a[9];

となります。

int b[100]; と宣言すると[]の数値は0から始まる決まりなので、0から99までの100個の変数を使うことができます。この場合 b[100] は使えません。

また、int b[100]; と宣言すると全部整数。float c[100]; と宣言すると全部浮動小数点数の配列になります。混ぜることはできません。

以下の課題は Hello.c と同様に実習します。

  1. エディタでプログラムを作り、指定されたファイル名(たとえばk0301.c)で保存します
  2. コンパイルします (たとえば ~/c$ gcc k0301.c -o k0301)
  3. 実行して結果を確認します。(たとえば ~/c$ ./k0301)
  4. コンパイルに失敗したり、実行結果が思わしくなければプログラムを修正して繰り返します。

課題3-1 配列変数の宣言・代入・参照

配列変数を使ったプログラムです。後に説明があります。

プログラム名 k0301.c

 1: /* 配列を使う: k0301.c */
 2: #include <stdio.h>
 3:
 4: int main()
 5: {
 6:    int a[5];
 7:    int sum;
 8:    a[0] = 10;
 9:    a[1] = 20;
10:    a[2] = 30;
11:    a[3] = 40;
12:    a[4] = 50;
13:    sum = a[0] + a[1] + a[2] + a[3] + a[4];
14:
15:    printf( "%d %d %d %d %d\n",a[0],a[1],a[2],a[3],a[4] );
16:    printf( "%d\n",sum );
17:
18:    return 0;
19: }

行頭の番号とコロン(:)は解説のためにつけてあるものなので、プログラムには入力しません。

文字はここからエディタにコピーできますが、不要な改行やスペースが一緒にコピーされるとコンパイルできなくなることがあります。コピー後に不要なものを削除したり訂正する必要がないか確認しましょう。

重要なところはコピーせず自分で入力したほうが記憶に残ります。

プログラム解説 k0301.c

6:int a[5]; 配列変数の宣言
aという名前の整数の配列変数を宣言します。要素の数は5個です。値はなにが入っているか分かりません。
a[0]a[1]a[2]a[3]a[4]
?????
7:
sum という名前の変数を宣言します。この名前(サム)は英語で合計のことです。
8:-12: 配列変数への代入
a[0]からa[4]に整数を代入しています。[]の中の数字は「添字」といいますが、0から始まるので要素の数が5であれば、a[4]までになります。
a[0]a[1]a[2]a[3]a[4]
1020304050
13: 配列変数の参照
a[0]からa[4]までの変数の値を取り出して足し算をして、sumという変数に代入します。
足し算は変数に入っている数値を見ながら(参照)別の場所(CPU)で行います。計算中は変数の値は変化しません。計算が終わるとその値をsumという変数に代入します。この代入でsumという変数の値が初めて変化します。
15:
a[0]からa[4]までの数値を表示します。
16:
sum の値を表示します。

実行結果は

~/c$ ./k0301 
10 20 30 40 50
150

繰り返しますがint a[5];と宣言した場合使える添字は4までです。つまりa[0]からa[4]までが使用出来ます。a[5]以上を使ってもコンパイルではエラーにならないかもしれません。でも、実行時にエラーを起こしたり、間違った結果を出したり、訳のわからない不具合がでたりします。何が起こるかわかりませんので十分注意してください。

また、一度も代入していない変数にはどんな値が入っているかはわかりませんから注意が必要です。

課題3-2 配列の初期化

配列を宣言すると同時に値を初期化します。k0301.c に比べて6行目がint a[5] = { 10, 20, 30, 40, 50 }になり、8〜12行目にあった代入がなくなりました。

プログラム名 k0302.c

 1: /* 配列の初期化: k0302.c */
 2: #include <stdio.h>
 3:
 4: int main()
 5: {
 6:    int a[5] = { 10, 20, 30, 40, 50 };
 7:    int sum;
 8:
13:    sum = a[0] + a[1] + a[2] + a[3] + a[4];
14:
15:    printf( "%d %d %d %d %d\n",a[0],a[1],a[2],a[3],a[4] );
16:    printf( "%d\n",sum );
17:
18:    return 0;
19: }

プログラム解説 k0302.c

6:int a[5] = {...}; 配列変数の宣言と同時に初期値を入れる
aという名前の整数の配列変数を宣言します。要素の数は5個です。{ } の中にコンマで区切って値を列挙します。

実行結果は同じです。

~/c$ ./k0302
10 20 30 40 50
150

次のように配列の要素数を省略することもできます。自動的に必要数が確保されます。

int a[] = { 10, 20, 30, 40, 50 }

課題3-3 floatの配列

最初と最後以外かなりの部分が変わります。

プログラム名 k0303.c

 1: /* 配列の初期化: k0303.c */
 2: #include <stdio.h>
 3:
 4: int main()
 5: {
 6:    float hen[] = { 12.1, 20, 30.5 };
 7:
 8:    printf( "%f\n",hen[0]+hen[1]-hen[2] );
 9:    printf( "%f\n",hen[1]+hen[2]-hen[0] );
10:    printf( "%f\n",hen[2]+hen[0]-hen[1] );
11:    printf( "マイナスが一つもなければ三角形ができます。\n" );
12:
13:    return 0;
14: }

プログラム解説 k0303.c

6: floatの配列
int の代わりに float と書けばfloatの配列になります。C言語では変数名の後の [] が配列の印です。
hen が変数名です。3つの値は三角形の3辺の長さなので、「辺」からつけた名前です。
同時に値の代入(初期化)もしています。3つのデータを入れていますから、要素数が3の配列ができます。
8: 計算と結果表示
hen... の式は2つの辺の長さを足したものから他の1辺の長さを引きます。この結果を %f で表示します。
9:, 10:
8: と同様に他の2辺の組み合わせについても計算します。
11:
三角形ならばどの2辺の和も他の一辺より大きくなっています。3つの計算結果のうち一つでもマイナスになれば三角形として成り立たないのでそれを報告します。

実行結果です。

adachi@adachi-CF-Y7:~/c$ ./k0303 
1.600000
38.400000
22.600000
マイナスが一つもなければ三角形ができます。

あとでどれかがマイナスになった時と全部プラスの時で表示を変えることを学びます。

課題3-4 配列の配列

最初と最後以外かなりの部分が変わりますが、よく見ると同じことを繰り返しています。

2つの添字で項目を指定するので2次元配列といいます。今後の授業展開では k0303.c までで十分ですから、軽く流してください。

k0303.c の三角形を4つまとめて処理するものです。

プログラム名 k0304.c

 1: /* 配列の配列: k0304.c */
 2: #include <stdio.h>
 3:
 4: int main()
 5: {
 6:     float hen[4][3] = { {12.1, 20  , 30.5},
 7:                         {23.4, 43.1, 10.2},
 8:                         {20.4, 33.1, 20.2},
 9:                         {14.3, 25.3, 30.0} };
10:     int i;
11:
12:     i = 0;
13:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
14:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
15:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
16:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
17:
18:     i = 1;
19:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
20:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
21:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
22:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
23:
24:     i = 2;
25:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
26:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
27:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
28:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
29:
30:     i = 3;
31:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
32:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
33:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
34:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
35:
36:     return 0;
37: }

プログラム解説 k0304.c

6:-9: 配列の配列の宣言と初期化
float hen[3] を4つ用意したいのです。それを float hen[4][3] と書きます。
一個の hen[3] を初期化するには { 12.1, 20, 30.5 }と書きましたが、それが4個でfloat hen[4][3]なので、4つコンマで区切って並べ、{ } でくくります。
この場合見やすいように途中で改行することができます。コンパイラの時には { {12.1, 20 , 30.5},{23.4, 43.1, 10.2},....... と書いてあるとみなします。
hen[0][0]hen[0][1]hen[0][2]
12.12030.5
hen[1][0]hen[1][1]hen[1][2]
23.443.110.2
hen[2][0]hen[2][1]hen[2][2]
20.433.120.2
hen[3][0]hen[3][1]hen[3][2]
14.325.330.0
10:
i という変数は三角形の番号です。0,1,2,3 の値を入れて三角形を指定します。
12:
i に 0 を代入すると 13:-15:の hen[i][0] などは hen[0][0] になり、0番目の三角形の辺を表します。
13:-15:
0番三角形について、2つの辺の長さを足したものから他の1辺の長さを引きます。この結果を %f で表示します。第一の添字を[i]にしたおかげで、19:-21: や 25:-28, 31:-33 にコピーできます。
18:
i に 1 を代入すると 19:-21:の hen[i][0] などは hen[1][0] になり、1番目の三角形の辺を表します。

実行結果は

~/c$ ./k0304
1.600000
38.400000
22.600000
マイナスが一つもなければ三角形ができます。

56.299998
29.899999
-9.499999
マイナスが一つもなければ三角形ができます。

33.299997
32.900000
7.500002
マイナスが一つもなければ三角形ができます。

9.599999
40.999999
19.000001
マイナスが一つもなければ三角形ができます。

課題3-5 2次元配列の裏側

この例題は理解できなくてもかまいません。

k0304.c に比べて 6:-9: の中の { } がなくなっています。

プログラム名 k0305.c

 1: /* 配列の配列: k0305.c */
 2: #include <stdio.h>
 3:
 4: int main()
 5: {
 6:     float hen[4][3] = { 12.1, 20  , 30.5,
 7:                         23.4, 43.1, 10.2,
 8:                         20.4, 33.1, 20.2,
 9:                         14.3, 25.3, 30.0 };
10:     int i;
11:
12:     i = 0;
13:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
14:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
15:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
16:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
17:
18:     i = 1;
19:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
20:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
21:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
22:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
23:
24:     i = 2;
25:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
26:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
27:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
28:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
29:
30:     i = 3;
31:     printf( "%f\n",hen[i][0]+hen[i][1]-hen[i][2] );
32:     printf( "%f\n",hen[i][1]+hen[i][2]-hen[i][0] );
33:     printf( "%f\n",hen[i][2]+hen[i][0]-hen[i][1] );
34:     printf( "マイナスが一つもなければ三角形ができます。\n\n" );
35:
36:     return 0;
37: }

プログラム解説 k0305.c

6:-9: 配列の配列の宣言と初期化
float hen[3] を4つ用意したのは同じですが、初期化するのにデータが三角形ごとに分けられていません。改行はしていますが、実質は{ 12.1, 20, 30.5, 23.4, 43.1, 10.2,... } と続けて書いてあるだけです。
k0304.c { {12.1, 20 , 30.5},{23.4, 43.1, 10.2},.......
k0305.c { 12.1, 20 , 30.5, 23.4, 43.1, 10.2, .......
つまり、内部では次の様になっていて、[ ]内の2つの添字から【 】内の数字を計算しているのです。
[1][2]なら 1*3+2 と計算して【5】、[2][0]なら 2*3+0 と計算して【6】となります。
hen【0】hen【1】hen【2】 hen【3】hen【4】hen【5】 hen【6】hen【7】hen【8】 hen【9】hen【10】hen【11】
12.12030.5 23.443.110.2 20.433.120.2 14.325.330.0

実行結果は同じです。

~/c$ ./k0304
1.600000
38.400000
22.600000
マイナスが一つもなければ三角形ができます。

56.299998
29.899999
-9.499999
マイナスが一つもなければ三角形ができます。

33.299997
32.900000
7.500002
マイナスが一つもなければ三角形ができます。

9.599999
40.999999
19.000001
マイナスが一つもなければ三角形ができます。

聖愛中学高等学校
http://www.seiai.ed.jp/
Nov. 2011