引数のポインタ周り（配列，ベクタ，ベクタのコピー）

※この記事では，Ubuntu16.04にインストールしたg++コンパイラで実行しています．

C++で関数にポインタを渡して計算するときに，いつも試行錯誤しながら（エラー出しながら）やっているので，整理して，メモ．

#### 基本
まず，はじめに基本編．int型の受け渡し．

```
#include <iostream>
#include <vector>
using namespace std;   /// この三行は以下共通

void sum(int n){    /// 値を引数とする
    n = n + 3;
}
void sump(int* n){  // アドレスを引数とする
    *n = *n + 3;    // 値で足し算
}

int main(int argc, char** argv) { // 以降は省略
    int n = 5;
    cout << "0) n= " << n << endl; // n=5
    sum(n);     // 値の足し算
    cout << "1) n= " << n << endl; // 反映されない(n=5のまま)

    sump(&n);   // アドレスで渡す
    cout << "2) n= " << n << endl;// 反映される(n=8)

    int* m; // アドレスで宣言
    m = &n; // nのアドレスをコピー
    cout << "3) m= " << *m << endl;
    sump(m);    // "m"がアドレスを示す
    cout << "4) m= " << *m << endl;
    cout << "5) n= " << n << endl;// nにも反映されている(同じアドレスなので)
    
    return 0; // 以降は省略
}
```
関数sumは値で受け渡しているのでmain関数では反映なし，sumpのようにアドレスで渡すと反映できます．

#### 配列の要素
つづいて，同じく，sum, sumpを使って，配列の要素について計算．

```main.cpp
    int ar[2] = {20, 18};
    cout << "ar[0]= " << ar[0] << endl;
    sum(ar[0]);     // 値の足し算
    cout << "ar[0]= " << ar[0] << endl; // 反映されない

    sump(&ar[0]);   // アドレスで渡す
    cout << "ar[0]= " << ar[0] << endl;
    sump(ar);   // 先頭アドレスを渡す
    cout << "ar[0]= " << ar[0] << endl;
    
    cout << "ar[1]= " << ar[1] << endl;
    sump(ar+1);   // アドレスで渡す
    cout << "ar[1]= " << ar[1] << endl;
```
配列要素のアドレスの渡し方は，ここでは，"&ar[x]"と"ar+x"の二つを使っています．
"&ar[x]"と関数に渡して，関数の引数としては"(int* n)"と受ける．関数内では，"(int)\*n"と使う．この辺でよく混乱します．
ちなみに，**ア**ン**ド**は**アド**レス，**ア**ス**タ**リスクは**あた**いと覚えるそうです．あとは，独自ですが，"int* n"とみてnはintのポインタ，"int *n"とみて*nはintとイメージしています．

#### ベクタの要素
つづいて，sum, sumpを使って，ベクタの要素について計算．

```main.cpp
    std::vector<int> vec(2);
    vec[0] = 111;
    vec[1] = 121;
    cout << "vec[0]= " << vec[0] << endl;
    sum(vec[0]);
    cout << "vec[0]= " << vec[0] << endl; // 反映されない
    sump(&vec[0]);   // アドレスで渡す
    cout << "vec[0]= " << vec[0] << endl;
    sump(vec.data());   // 先頭アドレスを渡す
    cout << "vec[0]= " << vec[0] << endl;
    cout << "vec[1]= " << vec[1] << endl;
    sump(vec.data()+1);   // アドレスを渡す
    cout << "vec[1]= " << vec[1] << endl;
```
ベクタ要素のアドレスの渡し方は，ここでは，"&vec[x]"と"vec.data()+x"の二つを使っています．

#### 配列・ベクタ
次に，配列，ベクタごとの計算．新たに関数を定義して，

```
void sumarray(int ar[], int length){ // 配列の長さは自分で指定
    for(int i = 0; i < length; ++i) ar[i] += 3;
}
void sumvec(vector<int> &vec){
    for(int i = 0; i < vec.size(); ++i) vec[i] += 3;
}
int main(int argc, char** argv) {
    // 初期化はそのまま

    cout << "ar[0]= " << ar[0] << " ar[1]= " << ar[1] << endl;
    sumarray(ar, 2); // 先頭のアドレスを渡す
    cout << "ar[0]= " << ar[0] << " ar[1]= " << ar[1] << endl;
    cout << "vec[0]= " << vec[0] << " vec[1]= " << vec[1] << endl;
    sumvec(vec);　// 先頭のアドレスを渡す
    cout << "vec[0]= " << vec[0] << " vec[1]= " << vec[1] << endl;
```
配列ではsump(ar)もsumarray(ar, 2)もOKですが，ベクタではsump(vec)はダメで，sumvec(vec.data())もダメです．引数の指定が違うので．

ベクタの場合は，イテレータを使う方法もあります．

```
void sumvecitr(vector<int> &vec){
    vector<int>::iterator itrvec = vec.begin(); // イテレータ
    for(; itrvec != vec.end(); ++itrvec){
        *itrvec += 3;
    }
}
//
sumvecitr(vec);
//
```
で計算できます．

####ベクタ（関数内コピーあり）
やっと本題．関数内でベクタをコピーして計算する場合．

```
void sum_ncpvec(vector<int> &vec){
    vector<int> cpvec = vec; // コピー
    for(int i = 0; i < cpvec.size(); ++i){
        cpvec[i] += 3;
    }
}
void sum_cpvec(vector<int> &vec){
    vector<int>* cpvec = &vec; // アドレスコピー
    for(int i = 0; i < (*cpvec).size(); ++i){
        (*cpvec)[i] += 3;
    }
}

int main(int argc, char** argv) {
    // 初期化はそのまま
    sum_ncpvec(vec);
    cout << "vec[0]= " << vec[0] << " vec[1]= " << vec[1] << endl;  // 反映されない
    sum_cpvec(vec);
    cout << "vec[0]= " << vec[0] << " vec[1]= " << vec[1] << endl;
```
当然ですが，sum_ncpvecは関数内でのコピー・計算なので，mainでは反映されません．反映したい場合は，アドレス(&vec)をvector\<int>* cpvecにコピーする必要があります．関数内の計算では，(*cpvec)をvector\<int>として扱います．

コピーしなくてもよい場合は多いと思いますが，vector<クラス>を扱っていて，自作クラス内のメンバ変数を読んだりすると，どんどん文が長くなるのでコピーしたら嵌ったので，整理しました．

####参考
直接的な引用はないですが，参照はこちら．
[C言語の引数に多次元配列を渡す](https://qiita.com/Hiraku/items/babed27bc1d750c2e12d)
[C++ 動的配列クラス std::vector 入門 - イテレータ](http://vivi.dyndns.org/tech/cpp/vector.html#iterator)
[新C言語入門 ビギナー編](http://www.sbcr.jp/products/4797325615.html)