C++ ２次元配列について ポインタと関数 No2

#目次
1.ポインタと２次元配列
1-1.２次元配列のポインタ 基本
1-2.２次元配列を指すポインタ
1-3.２次元配列を指すポインタ　補足
2.２次元配列と関数

#1.ポインタと２次元配列
1-1.２次元配列のポインタ
まずC言語ではメモリの取り方が行中心であること（正確な言い方は忘れた）に注意。a[3][3]で配列をとったら、メモリの取り方の順番は(0,0)(0,1)(0,2)(1,0)(1,1)(1,2)(2,0)(2,1)(2,2)になる。（Fortranだと違う）

つまりa[i][j] = \*(a[i] + j) = \*( \*(a+i) + j )

```c++:sample1.cpp
#include <bits/stdc++.h>
using namespace std;

#define FOR(i,a,b) for(int i = (a); i < (b); ++i)
#define rep(i,n) FOR(i,0,n)

int main(int argc, char const *argv[])
{
	cin.tie(0);
	ios::sync_with_stdio(false);

        int row = 4;	//行
	int col = 5;	//列
	//行列。左側が行。右側が列。
	int a[row][col]={ {11, 12, 13, 14, 15},
				  {21, 22, 23, 24, 25},
				  {31, 32, 33, 34, 35},
				  {41, 42, 43, 44, 45} };

	rep(i, row){
		rep(j, col){
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	rep(i, row){
		rep(j, col){
			cout << *(a[i] + j) << " ";
		}
		cout << endl;
	}
	cout << endl;

	rep(i, row){
		rep(j, col){
			cout << *( *(a + i) + j) << " ";
		}
		cout << endl;
	}
	cout << endl;

	return 0;
}
```
```c++:出力
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45

11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45

11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45
```

#1-2.２次元配列を指すポインタ
2次元配列をポインタで扱う方法
・その1
__ポインタの配列__を使う方法。int *p[row]と宣言し、それぞれの要素が２次元配列の各行の先頭要素のアドレスを格納する。

・その2(こっちは上手くいかない)
__配列全体を指すポインタ__を定義する方法。２次元配列の行ベクトルをそのまま記録して、その配列全体をポインタが指す。

この時、ポインタのサイズ（メモリ領域の大きさ）とポインタが指してるデータサイズは異なる。

```c++:sample2
#include <bits/stdc++.h>
using namespace std;

#define FOR(i,a,b) for(int i = (a); i < (b); ++i)
#define rep(i,n) FOR(i,0,n)

int main(int argc, char const *argv[])
{
	cin.tie(0);
	ios::sync_with_stdio(false);

	int row = 4;	//行
	int col = 5;	//列
	//行列。左側が行。右側が列。
	int a[4][5]={ {11, 12, 13, 14, 15},
				  {21, 22, 23, 24, 25},
				  {31, 32, 33, 34, 35},
				  {41, 42, 43, 44, 45} };

	int *p1[row];
	int (*p2)[col];
	
	//その1
	rep(i, row)	p1[i] = a[i];	//各行（1次元配列）の先頭アドレスをセット

	cout << "\nポインタ *p1[row]：ポインタ変数の配列\n";
    cout << "配列ポインタのサイズ: sizeof(p1) = " << sizeof(p1) << endl;
    cout << "要素ポインタのサイズ: sizeof(p1[0]) = " << sizeof(p1[0]) <<  endl;
    cout << "要素ポインタが指しているサイズ: sizeof(*p1[0]) = " << sizeof(*p1[0]) <<  endl;

	rep(i, 4){
		rep(j, 5){
			cout << *p1[i] + j << " ";
		}
		cout << endl;
	}
	cout << endl;

	rep(i, 4){
		rep(j, 5){
			cout << p1[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	//その2
	/*
	p2 = &a[0];

	cout << "\nポインタ (*p2)[col]：ポインタ変数の配列\n";
    cout << "配列ポインタのサイズ: sizeof(p2) = " << sizeof(p2) << endl;
    cout << "要素ポインタのサイズ: sizeof(p2[0]) = " << sizeof(p2[0]) <<  endl;
    cout << "要素ポインタが指しているサイズ: sizeof(*p2[0]) = " << sizeof(*p2[0]) <<  endl;

	rep(i, row){
		cout << *p2[i] << " ";
		cout << endl;
	}
	cout << endl;

	rep(i, row){
		rep(j, col){
			cout << p2[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
	*/

	return 0;
}
```
```c++:出力
ポインタ *p1[row]：ポインタ変数の配列
配列ポインタのサイズ: sizeof(p1) = 32
要素ポインタのサイズ: sizeof(p1[0]) = 8
要素ポインタが指しているサイズ: sizeof(*p1[0]) = 4
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45

11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45
```

またメモリは1次元的に並んでいて、行の区切りに関する情報を持たないのでアドレス計算をして参照することも可能

```c++:sample3.cpp
#include <bits/stdc++.h>
using namespace std;

#define FOR(i,a,b) for(int i = (a); i < (b); ++i)
#define rep(i,n) FOR(i,0,n)

int main(int argc, char const *argv[])
{
	cin.tie(0);
	ios::sync_with_stdio(false);

	int row = 4;	//行
	int col = 5;	//列
	//行列。左側が行。右側が列。
	int a[4][5]={ {11, 12, 13, 14, 15},
				  {21, 22, 23, 24, 25},
				  {31, 32, 33, 34, 35},
				  {41, 42, 43, 44, 45} };

	int *p;
	
	p = &a[0][0];
	

	rep(i, row){
		rep(j, col){
			cout << *(p + i * col + j)  << " ";
		}
		cout << endl;
	}
	cout << endl;

	rep(i, row){
		rep(j, col){
			cout << p[ i* col + j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	return 0;
}
```
```c++:出力
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45

11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45
```


#２次元配列と関数

2次元以上の配列を引数にする場合は、2番目の次元以降のサイズを指定しなければならない。またポインタ渡しをして、アドレス計算をして参照する方法もある。

```c++:sample4.cpp
#include <bits/stdc++.h>
using namespace std;

#define FOR(i,a,b) for(int i = (a); i < (b); ++i)
#define rep(i,n) FOR(i,0,n)

void rewrite1(int map[][3]);
void rewrite2(int *);

int main(int argc, char const *argv[])
{
	cin.tie(0);
	ios::sync_with_stdio(false);

	int row = 2;	//行
	int col = 3;	//列
	//行列。左側が行。右側が列。
	int a[2][3]={ {11, 12, 13},
				  {21, 22, 23} };

	rewrite1(a);

	rep(i, row){
		rep(j, col){
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	rewrite2(&a[0][0]);

	rep(i, row){
		rep(j, col){
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	return 0;
}

void rewrite1(int map[][3]){

	rep(i, row){
		rep(j, col){
			map[i][j] += 10;
		}
	}
}

void rewrite2(int *p){

	rep(i, row){
		rep(j, col){
			*(p + i * 3 + j) += 10;
		}
	}
}
```
```c++:出力
21 22 23
31 32 33

31 32 33
41 42 43


```



#参考文献
[関数](http://www.cc.kyoto-su.ac.jp/~yamada/programming/function.html)
[数値計算以前 #2.5 ２次元配列とポインタ](http://www.asahi-net.or.jp/~uc3k-ymd/Lesson/index01.html)