c++で固定長配列[]に長さのわからないデータを入れ、さらに関数の戻り値にしてみよう

# 0.要約
固定長配列[]に可変長データを書き込みたければ次のようにする。
(`recv`は引数として渡された`char`型配列に値を書き込む任意の関数)

```c++
#include<iostream>
#include<vector>
#include<string.h>

int main()
{
    int response_size = 10, int timeout=500;
    std::vector<char> v = std::vector<char>(response_size, '0');//vectorで動的確保。
    char* char_arr = &v[0];// vのアドレス(に入った値のアドレス)をchar配列のアドレスとする。
    recv(char_arr, response_size, timeout);//char配列にレスポンスが流し込まれる。

    //以降、char_arrは、あたかも
    //char char_arr[response_size] = {0};
    //のように宣言されたかのように利用することが出来る。

    return 1;
}
```
これは、`vector`内のメモリ配置と固定長配列のメモリ配置が同じであることを利用したトンチである。

関数fの戻り値にしたい場合は、ベクトル`v`をグローバル変数にするだけでよい。
具体例は次の通り。

```c++
#include<iostream>
#include<vector>
#include<string.h>

std::vector<char>　v;
char* f(int response_size, int timeout)
{
    v = std::vector<char>(response_size, '0');//vectorで動的確保。
    recv(&v[0], response_size, timeout);//レスポンスが流し込まれる。

    //以降、vは、あたかも
    //char型固定長配列であるかのように利用することが出来る。

    return &v[0];
}
```



# 1.どんな時に役立つか(想定例)
vectorを使って処理したいのに、何らかの理由で配列しか使えない場合など。

例えばwifi通信モジュールをマイコンから操作するプログラムをマイコンへ書き込んでいるとする。
通信モジュールのライブラリには、HTTPレスポンスを受け取る関数
`void recv(char* buf, int len, int timeout)`
が用意されているとする。

この関数は`len`[byte]未満のデータを受け取った場合、
それをchar配列`buf`に入れてくれるが、それ以上のデータを受け取った場合、データは途中で途切れてしまう。

今、関数`recv`を使って、HTTPレスポンスを返却する
`char* get_response(int response_size, int timeout)`
を作るとする。(リクエストは別の関数で既に送信済みであるものとする)


```c++
#include<iostream>

char* get_response(int response_size, int timeout)
{
    char buf[response_size] = {0};
    recv(buf, timeout);
    return buf;
}

```
のようにすることはできない。`buf`のサイズを`response_max_size`という**変数**で指定すると、CやC++では怒られるのだ。(だから固定長配列という。)

# 2.解決策とその理論

**グローバルな**`vector`を利用すればよい。

```c++
#include<iostream>
#include<vector>
#include<string.h>

std::vector<char> v;//とても大事です
char* get_response(int response_size, int timeout)
{
    v = std::vector<char>(response_size, '0');//vectorで動的確保。
    char* char_arr = &v[0];// ★vのアドレス(に入った値のアドレス)をchar配列のアドレスとする。
    recv(char_arr, response_size, timeout);//char配列にレスポンスが流し込まれる。
    return char_arr;
}
```

このようにすると、配列のサイズを指定することなく、`char*`型のレスポンスを得ることが出来る。

## 2-1. 全体説明

やっていることとしては、まず`vector`によって動的にメモリを確保し、
`v[0]`から`v[response_size]`まですべてに`'0'`を代入しておく。
次にそのメモリを**あたかも固定長配列の物であるかのように偽装工作する(★)**。
`char* char_arr = &v[0];`とすることで、
「配列`char_arr`のアドレスを『`v`のアドレス**に入った値`v[0]`』のアドレス**にせよ」ということになる※(2-4節「蛇足」も参考になるかも)。
『`v`のアドレスに入った値』は`char`型なので、そのアドレスは`char*`となり、辻褄が合うのである。
以上により、
`char_arr[0] == v[0]`が、
`char_arr[1] == v[1]`が、
...
`char_arr[response_size] == v[response_size]`が
約束される。 



## 2-2. vectorの利点

さて、`char_arr[i]`は固定長配列であって、`v[i]`はベクトルである。
`char_arr[0] == v[0]`が成立するのはよいにしても、
なぜ`char_arr[1以降] == v[1以降]`までもが成立するのだろうか。
この謎は、固定長配列やベクトルが、どのようにしてメモリを確保するかを知ることで解決する。
まず、固定長配列において、`&char_arr[i]`は`&char_arr[0]+i`と等価である。
つまり、`char_arr[0]`, `char_arr[1]`, `char_arr[2]`のアドレスは
`char_arr+0`, `char_arr+1`, `char_arr+2`のように**隣り合っている**。
これと全く同じことが、実は**ベクトルにおいても言える**。
すなわち`v[0]`, `v[1]`, `v[2]`のアドレスは
`&v[0]+0`, `&v[0]+1`, `&v[0]+2`のようになっている。
`char_arr = &v[0];`とすることで、
`char_arr+i == &v[0]+i;`が約束されることはすぐにお分かりいただけるだろう。
そしてその意味は、
`char_arr[i]のアドレス == v[i]のアドレス`
なのである。

## 2-3. グローバルにする利点

ソースコードにおいて、ベクトル`v`はグローバル変数となっている。
グローバル変数とは、関数の外で宣言されているがために、関数終了後にも引き続き有効である変数のことである。
この性質が、実は`char_arr`を支えている。例えるなら`v`が`char_arr`を延命治療しているのである。
`char_arr`は関数`get_response(int, int)`の内部で定義されている。
つまり、**本来、返却値は、返却後ただちに死ぬ**のである。
(そんなことが起きた場合の)事態の深刻さが分かるだろうか。`get_response`関数をペットショップに例えるのなら、
このショップは、販売後ただちに死ぬような動物を、顧客に売りつけるのである。
ペットショップ内でしか生きられない動物を治療し、顧客の家でも元気に走り回れるようにしてくれているのが、グローバル変数`v`なのである。

`char_arr`の各要素は、`v`の各要素と同じアドレスを持つのであった。
つまり、関数が`char_arr`を返却し、「`char`型の配列(の先頭要素のアドレス)です」と言い張っているのは、
実はベクトル`v`の先頭要素のアドレスを返却しているのである。
そしてこの`v`はグローバルであるからこそ、関数外に出ても生き続けるため、全く同じ実体である`char_arr`も生き続けるのである。
実際3-1節にて、「関数内で`char_arr`を定義せず、すべて`&v[0]`で代用しても、振る舞いは全く同じである」ことを検証している。

また3-2節では、「`v`をグローバルでない変数(ローカル変数)に置き換えた場合どうなってしまうのか」という検証も行っている。


## 2-4.蛇足
ベクトル`v`では、配列と違い、`v`が`&v[0]`と等価であるとは保証されていないため、
`char* char_arr = v;`としてはいけない。
一方、固定長配列`char_arr`では`char_arr`が`&char_arr[0]`と等価であることが保証されているので、
`char_arr = &v[0];`は
`*char_arr = *(&v[0]);`つまり
`*(&char_arr[0]) = *(&v[0]);`とみることができるから、
`char_arr[0] = v[0];`のように考えることが出来るのである。</sub></sub>

さらに蛇足して、
「`char_arr = &v[0];`なんて捻くれた書き方せずとも、
`&char_arr[0] = &v[0];//A`とか
`char_arr[0] = v[0];//B`とか
`char_arr = v;//C`でいいじゃないか」
という疑問に答えよう。
Aは「演算子`&`が左辺に来るなんてダメだから」である。
Bでは`v[0]`の値が`char_arr[0]`へコピーされるだけで終わってしまう。
`v[1]`以降が`char_arr[1]`以降へコピーされるという反応が起こらないのである。
Cでは抽象的過ぎる。ベクトルのアドレスを可変長配列のアドレスへ代入しようとしても、そもそも型が異なるため、おそらくコンパイルも通らないだろう。


# 3.実験

実際に動作するソースコード全体は次の通り。
(`recv`関数は、常に「hello world」を返すものとする)

```c++:test.cpp
#include <iostream>
#include <vector>
#include <string.h>

char response_[] = "hello world";//今回はrecvは常に「hello world」を返すものとする。
char resp_err[] = "";//但し、サイズが足りない場合、空文字列を返却する。
void recv(char* char_arr, int size, int timeout)
{
    if(strlen(response_) < size)
        for(int i=0; i < strlen(response_)+1; i++)
            char_arr[i] = response_[i];
    else
        for(int i=0; i < strlen(resp_err)+1; i++)
            char_arr[i] = resp_err[i];
}

std::vector<char> v;//とても大事です
char* get_response(int response_size, int timeout)
{
    v = std::vector<char>(response_size, '0');//vectorで動的確保。
    char* char_arr = &v[0];// ★vのアドレス(に入った値のアドレス)をchar配列のアドレスとする。
    recv(char_arr, response_size, timeout);//char配列にレスポンスが流し込まれる。
    return char_arr;
}


bool truncated(const char* response){return strlen(response)==0;}

int main()
{
    int size;
    int limit = 100;
    const char* response;
    for(size = 1; size < limit; size++)
    {
        response = get_response(size, 100);
        if(!truncated(response))break;
    }
    if(size >= limit)
        printf("error: response size too long.");
    else
        printf("ok: '%s', where size is %d", response, strlen(response));

}
```

`main`関数内の変数`limit`が13以上である場合、

```
ok: 'hello world', where size is 11
```
のように表示される。
`limit`を12以下にすると、次のようになる。

```
error: response size too long.
```

## 3-1. 追加実験1

`get_response`関数を次のように書き換えても、まったく同じ結果を得る。

```c++:get_response関数の別のパターン
std::vector<char> v;//とても大事です
char* get_response(int response_size, int timeout)
{
    v = std::vector<char>(response_size, '0');//vectorで動的確保。
    recv(&v[0], response_size, timeout);//vectorにレスポンスが流し込まれる。
    return &v[0];
}
```

この書き換えでは、`char_arr`を定義するのをやめ、すべて`&v[0]`で代用するものである。
両者の実体は全く同じなのだから、結果に影響を及ぼさないのは当然である。

## 3-2. 追加実験2
グローバルな`vector`をローカルに変えた場合にどのような結果を得るか、実験する。
そのために、`get_response`関数を次のように書き換える。

```c++:不良なget_response関数

char* get_response(int response_size, int timeout)
{
    std::vector<char> v = std::vector<char>(response_size, '0');//vectorで動的確保。
    char* char_arr = &v[0];// ★vのアドレス(に入った値のアドレス)をchar配列のアドレスとする。
    recv(char_arr, response_size, timeout);//vectorにレスポンスが流し込まれる。
    return char_arr;
}
```

結果、次のような表示を得た。

```
ok: 'ﾀks', where size is 3
```
これは、メモリをローカル変数として確保したことにより、`get_response`関数の処理が終了した後、処理系によって自動的に無関係の値を上書きされてしまったために起きたものである。