配列の概要

配列の概要


サイト全体の目次

稿


稿

配列

このセクションのソース

/*01*/ #include <stdio.h>
/*02*/ 
/*03*/ main()
/*04*/ {
/*05*/   int x[16];
/*06*/   int n;
/*07*/   int total = 0;
/*08*/ 
/*09*/   for(n = 0; n < 16; n++){
/*10*/     x[n] = n*n;
/*11*/     total += x[n];
/*12*/   }
/*13*/ 
/*14*/   for(n = 0; n < 16; n++){
/*15*/     printf("x[%d] = %d\n", n, x[n]);
/*16*/   }
/*17*/ 
/*18*/   printf("合計は %d です。\n", total);
/*19*/ 
/*20*/   return 0;
/*21*/ }

list-3.1.1-05

配列を宣言しています。

int x[n];

のように宣言すると、メモリ上に連続的に int 型のn個の変数 x[0]、x[1]、x[2]、x[3]、・・・、x[n-1] が作られます。ここで注意して欲しいのは作られる変数が x[0] からなので最後の変数は x[n-1] になることです。また、このように連続した変数を配列といい、各変数を識別するためにつけられている [~] を添字(そえじ)といいます。この例だと x[0] から x[15] までの int 型変数16個が作られるわけです.。また、配列はそれぞれの x[~] を見れば普通の変数と同様に扱えます。

int x[4];    と宣言すると、メモリ上には

   |<------  x[0]  ------->|<------  x[1]  ------->|
-----------------------------------------------------
...| 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 |
-----------------------------------------------------
   |<---  int (4byte)  -</C>|

 |<------  x[2]  ------->|<------  x[3]  ------->|
-----------------------------------------------------
 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 |...
-----------------------------------------------------

のように確保されます。
				

list-3.2.1-09

さて、初期化の方法なのですがいくつかあります。宣言と同時に初期化する時は

int x[5] = {12,15,14,47,98}

のように「 { } 」で囲んで、各要素を「,」で区切ってかきます。ですが、宣言時以外で初期化するにはそれぞれの要素を書いて
x[0] = 12;
x[1] = 15;
x[2] = 14;
x[3] = 47;
x[4] = 98;

のようにしなければいけません。しかし大きな配列を初期化したい時などは、これらはあまり効率的ではありませんね。そこで、配列の添字には数値変数を使うことが出来ます。これを利用すれば、for 文を使って効率よく初期化できます。
for(n = 0; n < 16; n++){    /*2:*/
    x[n] = n*n;
    total += x[n];
}

この例では for 文を使って、各 x[n] を n の自乗に初期化しています。最初のループでは「x[0] = 0*0」、次のループでは「x[1] = 1*1」、次は「x[2] = 2*2」、・・・、といったふうに。この方法を使えば、大きな配列をとりあえずすべて「0」に初期化したいときなどに有効です。

多次元配列

このセクションのソース

次は多次元配列についてです。添字をいくつも書いたものを多次元配列といいます。

/*01*/ #include <stdio.h>
/*02*/ 
/*03*/ main()
/*04*/ {
/*05*/   int x[3][5];
/*06*/   int i,j;
/*07*/ 
/*08*/   for(i = 0; i < 3; i++){
/*09*/     for(j = 0; j < 5; j++){
/*10*/       x[i][j] = i + j;
/*11*/     }
/*12*/   }
/*13*/ 
/*14*/   for(i = 0; i < 3; i++){
/*15*/     for(j = 0; j < 5; j++){
/*16*/       printf("x[%d][%d] = %d\n", i, j,x[i][j]);
/*17*/     }
/*18*/   }
/*19*/ 
/*20*/   return 0;
/*21*/ }

list-3.2.2-05

このように添字を2つ以上使って配列を宣言するとどうなるでしょう?これを理解するためには縦が3、横が5の表を考えるとよいでしょう.

---------------------------------------------------
| x[0][0] | x[0][1] | x[0][2] | x[0][3] | x[0][4] |
|---------|---------|---------|---------|---------|
| x[1][0] | x[1][1] | x[1][2] | x[1][3] | x[1][4] |
|---------|---------|---------|---------|---------|
| x[2][0] | x[2][1] | x[2][2] | x[2][3] | x[2][4] |
---------------------------------------------------
	

今までは直線(1次元)的なイメージだった配列が平面(2次元)的なイメージになるわけです。そして、それぞれについてはやはり普通の変数同様に扱えますし、添字に数値変数を使うことも出来ます。もちろん「int x[15];」として、15個の箱を作ってもかまいませんが場合によってはグループ分けしたい時もあるでしょう。そのような時にはこういった使い方をすると便利かもしれません。

ですが、直線的なメモリ上ではどのように確保されるのでしょうか?こういった場合、まず一番右の添字から考えていきます。つまり、上の表を「上段」「中段」「下段」の順に横に並べた感じで、x[0][0]~x[0][4],x[1][0]~x[1][4],x[2][0]~x[2][4] という順番で連続的に確保されます。整数が繰り上がっていくのといっしょですね。

また、初期化をする場合、08行目のように添字に数値変数を使って for 文により初期化する場合がほとんどかもしれませんが、宣言時に初期化することもできます。その場合、

int x[2][3] = {{3,4,6},{2,7,5}};

という形になります。

さて、「多次元配列」といったからには添字を3つ、4つ、5つ、・・・、とすることもできます。その場合、例えば3次元配列なら「int x[7][3][10];」のように宣言し、上の表は立体(3次元)になる感じです。メモリ上の確保も2次元と同様一番右の添え字から考えていき、整数が繰り上がっていく感じの順に確保されます。

では、これ以上の次元はあまり使わないでしょうが、4次元は上の表をどう考えるのでしょうか?「立体に時間軸を加えたものを想像すればいいのです。」・・・と言われても「はぁ?」ですよね。それに、「5次元は?」「6次元は?」と聞かれたら、それこそ分からないですよね。

実は、私はこの「次元」という考え方をあまりいいものではないと思っています。それよりも、Windows の「エクスプローラ」を想像してみてください。「フォルダ(ディレクトリ)」によって階層構造で管理されています。これをイメージすると大変分かりやすくなると思います。.を見てください。x[3][2][3] というドライブがあって階層的なフォルダによって管理されているように見えませんか?しかも、メモリ上には、上からこの順番どおりに確保されていきます。ちなみに、右側に書かれた数字は添字の部分だけをつなげて書いたものですが、まさに「整数の繰り上がり」といっしょですね。

x[3][2][3]                  
  |- x[0][][]
  |    |- x[0][0][]
  |    |    |- x[0][0][0]    000
  |    |    |- x[0][0][1]    001
  |    |    |- x[0][0][2]    002
  |    |
  |    |- x[0][1][]
  |         |- x[0][1][0]    010
  |         |- x[0][1][1]    011
  |         |- x[0][1][2]    012
  |
  |- x[1][][]
  |    |- x[1][0][]
  |    |    |- x[1][0][0]    100
  |    |    |- x[1][0][1]    101
  |    |    |- x[1][0][2]    102
  |    |
  |    |- x[1][1][]
  |         |- x[1][1][0]    110
  |         |- x[1][1][1]    111
  |         |- x[1][1][2]    112
  |
  |- x[2][][]
       |- x[2][0][]
       |    |- x[2][0][0]    200
       |    |- x[2][0][1]    201
       |    |- x[2][0][2]    202
       |
       |- x[2][1][]
            |- x[2][1][0]    210
            |- x[2][1][1]    211
            |- x[2][1][2]    212
	

この考え方からすると「多次元配列」ではなく「多階層配列」と言ったところでしょうか。そもそも人間は、3次元空間でさえイメージするのが大変なんですから、「多次元」で理解するのには限界があります。でも、配列を「階層」でイメージすれば、どんなに添字が増えてもその分だけ階層を深くしてイメージすればいいわけで、「~次元」なんて考えるよりずっと分かりやすいのではないかと思います。もっとも、こんな複雑怪奇な配列を使うことはほとんど無いことでしょうが。

練習問題

問題-3.2.1

最大で 20 個の整数データを入力し、それらの総和を求めてください。

問題-3.2.2

最大で 20 個の整数データを入力し、それを小さい順に並べ替えてください。
ヒント:Ans06-3-2を参考にしてみてください。

練習問題回答例

問題-3.2.1

#include <stdio.h>

main()
{

	int wa, data[20];
	int i, n;

	printf("データ数 -> ");
	scanf("%d", &n);

	for(i = 0; i < n; i++){
		printf("data[%d] -> ", i);
		scanf("%d", &data[i]);
	}

	wa = 0;
	for(i = 0; i < n; i++){
		wa += data[i];
	}

	printf("総和は %d です。\n", wa);

	return 0;
}

問題-3.2.2

#include <stdio.h>

main()
{
	/* 次のような配列、変数を用意する
		data[20]	最大20個のデータが入る配列
		i, j		ループカウント用の変数
		n		データ数を入れておく
		tmp		二つのデータを入れ替える時の退避変数
	*/
	int data[20];
	int i, j, n, tmp;

	printf("データ数 -> ");
	scanf("%d", &n);

	for(i = 0; i < n; i++){
		printf("data[%d] -> ", i);
		scanf("%d", &data[i]);
	}

	/* 何セット目かをカウントするループ */
	for(i = 0; i < n; i++){
		/* 隣同士を比較するループ。例えば三つのデータを比較する時を
		考えてみればデータの比較回数は 2 回で 1 セットが終わる(n 個の
		データなら n - 1 回の比較で 1 セットが終わるということ)。
		さらに、 1 セット終わるとその時点で最後の配列には最大の値が
		入っているため、この最後部分は比較する必要がない。すなわち、
		n セット目では最後部分の n 回分は比較する必要がない。したがって、
		各セットでの比較回数は
			[データ数(n)] - [セットカウント(i)] - 1
		ということになる */
		for(j = 0; j < n - i - 1; j++){
			if(data[j] > data[j + 1]){
				tmp = data[j];
				data[j] = data[j + 1];
				data[j + 1] = tmp;
			}
		}
	}

	printf("並べ替えました。\n");
	for(i = 0; i < n; i++){
		printf("data[%d] -> %d\n", i, data[i]);
	}

	return 0;
}


読み込み中・・・
10秒待っても表示が変わらない場合、次の理由が考えられます。
・Javascript が無効になっています。
・検索エンジンのキャッシュを見ています。
サイトホームへ / 上位ページへ / ページトップへ / PAROFトレンドショッピングへ
Copyright (C) 2010 totobon all right reserved.