LoginSignup
10
6

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-05-03

目次

1.ポインタと2次元配列
1-1.2次元配列のポインタ 基本
1-2.2次元配列を指すポインタ
1-3.2次元配列を指すポインタ 補足
2.2次元配列と関数

1.ポインタと2次元配列

1-1.2次元配列のポインタ
まず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 )

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;
}
出力
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次元配列を指すポインタ

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

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

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

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;
}
出力
ポインタ *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次元的に並んでいて、行の区切りに関する情報を持たないのでアドレス計算をして参照することも可能

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

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;
        }
    }
}
出力
21 22 23
31 32 33

31 32 33
41 42 43


参考文献

関数
数値計算以前 #2.5 2次元配列とポインタ

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6