見出し画像

さっくりC言語_03 //多次元配列

 さっくりC言語の第三回目でございます、はい。
 今回はちょっと色々かっ飛ばして多次元配列のお話となります。この辺りはポインタとの関係が深いのですが、その辺諸々すっ飛ばして行こうかと思います。

前回の記事


2.一次元配列

 前回までの変数では文字列を扱うことが出来ませんでした。char単体では一文字分しか扱うことが出来ません。文字列を扱うためにはこの一文字を束ねる必要があります。この束ねる方法に配列があります。
 
 配列とは文字通り変数を一列に並べたものです。想像図としては大体こんな感じ。

配列

 配列には番号が割り振られています。ここで注意して欲しいのは、番号の割り振りが0から始まること、一番後ろの番号が、「配列の大きさ-1」になっているという点です。

 まあ、うだうだ説明するよりもコードを読んだり、動かしてみた方が速いと思いますので、まずはサンプルを見てみましょう。

#include<stdio.h>

int main(void) {
	int array[3];
	array[0] = 3;
	array[1] = 4;
	array[2] = 5;

	printf("%d %d %d \n", array[0], array[1], array[2]);

	return 0;
}

実行結果

3 4 5

 配列を作成する場合は、
変数 名前[大きさ]
と書きます。

 また、変数にアクセスする場合には[]内にアクセスしたい番号を書きます。

 初期化する際には{}を利用することができます。

#include<stdio.h>

int main(void) {
	int array[3] = {3, 4, 5};

	printf("%d %d %d \n", array[0], array[1], array[2]);

	return 0;
}

実行結果

3 4 5

 また、配列を作成する際に、わざと大きさを指定しない方法もあります。その際には、[]の中を空っぽのまま扱う事になります。

#include<stdio.h>

int main(void) {
	int array[] = {3, 4, 5};

	printf("%d %d %d \n", array[0], array[1], array[2]);

	return 0;
}

 この配列を利用して、文字列を取り扱うことができます。

 はい、では文字列を扱ってみましょう。こんな感じです。

#include<stdio.h>

int main() {
	char str[] = "これは文字列です";
	
	printf("%s\nバイト数: %zu\n", str, sizeof(str));

	return 0;
}

実行結果

これは文字列です
バイト数: 17

 一次配列を用いて文字列を表現することが出来ましたね。
 因みに文字列は何処までが文字列か識別するために、語尾に\0のヌル文字を付ける事になっています。日本語は一文字あたりに2バイト必要とするため合計で17文字になります。

  実際に\0文字がどの様に作用するのか確認してみましょう。

#include<stdio.h>

int main() {
	char str[] = "これは文字列です\0この文字列は表示されません";
	
	printf("%s\n文字数: %zu\n", str, sizeof(str));

	return 0;
}

実行結果

これは文字列です
文字数: 44

このように、\0から後ろの文字列をすべて無視する扱いをしています。しかしちゃんと、確保したメモリの大きさは17ではなく、44になっています。

3.二次元配列

 配列では面白いことに、配列の配列を作成することができます。と、いってもイメージは湧かないと思われます。(ぶっちゃけ筆者もたまによー分らんくなります)
 なので、まずイメージ図を見ていきましょう!!


二次元配列

 配列をまとめたものになります。行列を知っている方であればそれを思い浮かべてもらえば大丈夫です。二つの番号が割り振られていて、何番目の行の、何番目を示すかを番号として持っています。

 形式は、
  型 名前[番号][番号]
となります。

 これも、実際にコードを見た方が速いと思います。

#include<stdio.h>

int main() {
	int array[3][3];

	array[0][0] = 0;
	array[0][1] = 1;
	array[0][2] = 2;

	array[1][0] = 3;
	array[1][1] = 4;
	array[1][2] = 5;

	array[2][0] = 6;
	array[2][1] = 7;
	array[2][2] = 8;

	printf("%d %d %d\n", array[0][0], array[0][1], array[0][2]);
	printf("%d %d %d\n", array[1][0], array[1][1], array[1][2]);
	printf("%d %d %d\n", array[2][0], array[2][1], array[2][2]);
	printf("適当な番: %d\n", array[2][1]);

	return 0;
}

実行結果

0 1 2
3 4 5
6 7 8
適当な番: 7

 3*3の情報を持つ配列ですね。
 array[i][j]の番号に対して、i*(下の番号の大きさ)+ jの関係になっています。今回の場合は2*3+1で7、適当な数字の部分が0から数えて7番目になっているのが分かるかと思われます。

 初期化を行う場合は{}を複数回使って行います。
 大体次の感じ。

#include<stdio.h>

int main() {
	int array[3][3] = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8} };

	printf("%d %d %d\n", array[0][0], array[0][1], array[0][2]);
	printf("%d %d %d\n", array[1][0], array[1][1], array[1][2]);
	printf("%d %d %d\n", array[2][0], array[2][1], array[2][2]);
	printf("適当な番: %d\n", array[2][1]);

	return 0;
}


 ちょっと分かりにくいですが、3個の塊が3個集まってる感じです。(超ふんわり)。

 さて、では文字列を扱ってみましょう。複数の文字列を扱うと、辞書っぽくなって楽しいです。(個人的な感想です)

#include<stdio.h>

int main() {
	char str[][4] = {"Dog", "Cat", "Mob"};

	printf("%s\n", str[0]);
	printf("%s\n", str[1]);
	printf("%s\n", str[2]);

	return 0;
}

実行結果

Dog
Cat
Mob

3.多次元配列

 配列では二次元以上を扱うことも可能です。が、ぶっちゃけオススメはしません。プログラムで扱えるメモリの大きさは環境によって違いますが、基本的に有限です。さらに、一時的な変数などで扱えるメモリの数はもっと少ないのです。2次以上の場合、場合によっては、アホみたいなメモリを確保する必要が出てくる可能性があるのです。

 オーダーのO(n^3)は物凄い量です。たったn=10でも、扱うデータ量は1000個の量を扱う羽目になります。
 

 と、いう訳で3次の配列を見てみましょう……。

#include<stdio.h>

int main() {
	int array[3][3][3] = { { {1, 2, 3},    {4, 5, 6},    {7, 8, 9}   },
						   { {10, 11, 12}, {13, 14, 15}, {16, 17,18} },
						   { {19, 20, 21}, {22, 23, 24}, {25, 26, 27}} 
						 };

	printf("%d %d %d\n", array[0][0][0], array[0][0][1], array[0][0][2]);
	printf("%d %d %d\n", array[0][1][0], array[0][1][1], array[0][1][2]);
	printf("%d %d %d\n", array[0][2][0], array[0][2][1], array[0][2][2]);

	printf("%d %d %d\n", array[1][0][0], array[1][0][1], array[1][0][2]);
	printf("%d %d %d\n", array[1][1][0], array[1][1][1], array[1][1][2]);
	printf("%d %d %d\n", array[1][2][0], array[1][2][1], array[1][2][2]);

	printf("%d %d %d\n", array[2][0][0], array[2][0][1], array[2][0][2]);
	printf("%d %d %d\n", array[2][1][0], array[2][1][1], array[2][1][2]);
	printf("%d %d %d\n", array[2][2][0], array[2][2][1], array[2][2][2]);

	return 0;
}

実行結果

1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
25 26 27

 はい、という訳でこの辺で止めておきましょう。

4.結び

 以上多次元配列でした。
 色々書いてしまいました、配列とはとどのつまり、メモリが連続で連なったものです。

 また、配列は当然ですがメモリと密接な関係にあります。ですので、キャッシュの容量や、メモリのアクセス速度の関係でアクセス速度が遅くなったりもします。この辺の事情は仮想メモリで調べると出て来るかと思われます。

  これとは別に大きなメモリを扱うことのできる、動的なメモリ割り当ての方法があります。が、これは使用後にきちんとメモリの解放をする必要があるので結構気を使います。javeやらpythonやらなどは、その辺をケアしてくれるので有難いです。

次回の記事

この記事が気に入ったらサポートをしてみませんか?