topazの遊び場

いろいろやってみる

そろそろC++やるぞパート9 配列3 ~ 初期化と関数渡し ~

そろそろC++やります

そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。

という感じでやっています。

※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。

内容

  • Microsoft配列をベースに、配列の初期化と関数渡しついて行います。

配列の初期化

初期値を与えて、初期化することができます。

int ar[2]{13, 17};

=で繋いでも、初期化することができます。

int ar[2] = {13, 17};

初期化指定する要素が、配列の要素数を満たさない場合は、規定値となります。intの場合は0が規定値です。

int ar[2]{13};
// ar: {13, 0}
int ar[2] = {13};
// ar: {13, 0}
int ar[2]{};
// ar: {0, 0}

{ }を書かない場合は、メモリの位置にあるランダムな値が入るので注意が必要です。

int ar[2];
// ar: {49036572, 1}

for文で回して、各要素に代入して初期化する場合もあります。

int ar[2];
for (int i = 0; i < 2; i++)
{
    ar[i] = i * 3;
}

関数に配列を渡す

配列は関数に渡される時、最初の要素へのポインターとして渡されます。

void ReceiveArray(int *arArg)
{
    cout << "In ReceiveArray function" << endl;
    cout << &arArg << endl;
    cout << arArg << endl;
}

int main()
{
    int ar[2]{13, 57};
    cout << "In main function" << endl;
    cout << &ar << endl;
    ReceiveArray(ar);
    return 0;
}
// Output:
// In main function
// 0x16b5bedc0
// In ReceiveArray function
// 0x16b5bed88
// 0x16b5bedc0

いろいろ試したのですが、配列の変数(ararArg)のアドレス(&ar&arArg)はどこにあっても構わず、配列の変数の中身が、アドレスとなっており、それが配列の要素の最初のアドレスになっていることが大切ということが分かりました。
配列の要素へのアクセスを詳しく調べる必要がありそう です。

関数で渡されたポインターには、その他のサイズや型情報を持たないので、別のパラメータで要素の数を渡す必要があります。

void process(double *p, const size_t len)

C++の他の記事をみると配列のサイズは、sizeofを用いて計算できると書いてあることもあります。

int arrayLength = sizeof(arArg) / sizeof(int);

しかし、これを関数で渡された配列(ポインター)で行うと結果が異なります。sizeof(int);は、同じコンピューターで不変ですが、sizeof(ar)sizeof(arArg)の結果は異なります。

void ReceiveArray(int *arArg)
{
    cout << "=====In ReceiveArray function" << endl;
    cout << sizeof(arArg) << endl;
}

int main()
{
    int ar[4]{13, 57};
    cout << "=====In main" << endl;
    cout << sizeof(ar) << endl;
    ReceiveArray(ar);
    return 0;
}
// Output:
// =====In main
// 16
// =====In ReceiveArray function
// 8

sizeof(arArg)は、ポインターのサイズである8を返していました。
また、ポインター渡しなので配列の中身を変更することができます。

void ReceiveArray(int *arArg)
{
    arArg[0] = 321;
}

int main()
{
    int ar[4]{13, 57};
    cout << "=== Before call function" << endl;
    cout << ar[0] << endl;
    cout << ar[1] << endl;
    ReceiveArray(ar);
    cout << "=== After call function" << endl;
    cout << ar[0] << endl;
    cout << ar[1] << endl;
    return 0;
}
// Output:
// === Before call function
// 13
// 57
// === After call function
// 321
// 57

constキーワードをつけることで明示的に配列を変更不可能にすることができます。コンパイル時にエラーを吐くようになります。

void ReceiveArray(const int *arArg)
{
    // error: read-only variable is not assignable
    arArg[0] = 321;
}

また、配列の引数は以下の方法で宣言することもできます。

void ReceiveArray(int arArg[4])
{
}

参考リンク

感想

初期化は慣れればその書き方ができそうで、読む分には困ることはなさそうです。関数渡しについては、基本的に参照渡し(ポインター渡し)が行われて、配列の型情報や大きさは別で伝える必要があることに注意をすればよさそうです。

次回は、多次元配列を行います。