C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++のアレイディケイ(配列減衰)とは?発生原因と防止方法をわかりやすく解説

アレイディケイ(配列減衰)とは

アレイディケイ(Array Decay:配列減衰)とは、配列が本来持っている型情報や次元(サイズ)の情報が失われてしまう現象のことです。これは、配列を関数に「ポインタ」または「値」として渡したときに発生します。

配列を関数に渡すと、実際に渡されるのは配列全体ではなく、先頭要素のアドレスを示すポインタです。そのため、関数の中で sizeof を使っても、元の配列のサイズではなくポインタ自体のサイズが返されてしまいます。

アレイディケイの発生を確認するサンプルコード

次のC++のコードで、アレイディケイが実際にどのように起こるかを確認してみましょう。

#include <iostream>
using namespace std;

void DisplayValue(int *p) {
cout << "値渡しで渡した場合の配列サイズ : ";
cout << sizeof(p) << endl;
}

void DisplayPointer(int (*p)[10]) {
cout << "ポインタ渡しで渡した場合の配列サイズ : ";
cout << sizeof(p) << endl;
}

int main() {
int arr[10] = {1, 2};
cout << "配列の実際のサイズ : ";
cout << sizeof(arr) << endl;
DisplayValue(arr);
DisplayPointer(&arr);
return 0;
}

出力結果

配列の実際のサイズ : 40
値渡しで渡した場合の配列サイズ : 8
ポインタ渡しで渡した場合の配列サイズ : 8

int型10個分の配列なので、本来のサイズは 10 × 4バイト = 40バイトです。しかし、関数に渡した後はポインタになってしまうため、64ビット環境ではポインタ1個分の8バイトが返されています。このように、関数の中では元の配列サイズを知る手段がなくなってしまうのです。

アレイディケイを防ぐ2つの方法

C++でアレイディケイを防ぐには、主に以下の2つの方法があります。

  • 配列のサイズを別の引数として渡す:配列と一緒に要素数を渡し、関数内の配列パラメータに対して sizeof を使わないようにします。
  • 配列を参照渡しで渡す:参照で渡せば配列からポインタへの変換(減衰)が起こらないため、関数内でも元のサイズを正しく取得できます。

参照渡しでアレイディケイを防ぐサンプルコード

#include <iostream>
using namespace std;

void Display(int (&p)[10]) {
cout << "参照渡しで渡した場合の配列サイズ : ";
cout << sizeof(p) << endl;
}

int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << "配列の実際のサイズ : ";
cout << sizeof(arr) << endl;
Display(arr);
return 0;
}

出力結果

配列の実際のサイズ : 40
参照渡しで渡した場合の配列サイズ : 40

このように、配列を参照(int (&p)[10])として受け取ることで、関数内でも元の配列サイズである40バイトが正しく取得できていることがわかります。

補足:モダンC++での代替手段

なお、C++11以降では std::array を使うことで、サイズ情報を保持したまま配列をコンテナとして扱えます。また、C++20で導入された std::span を使えば、配列やコンテナの要素列をサイズ情報付きで安全に渡すことができ、アレイディケイの問題を根本的に回避できます。新しいコードでは、生の配列ではなくこれらの機能を活用するのがおすすめです。

  1. C++でコンソール画面をクリアする方法をわかりやすく解説

    C++のプログラムからコンソール(ターミナル)画面に表示された内容を消去したい場合、system()関数を使ってOSのコマンドを実行するのが一般的な方法です。この関数は標準ライブラリ<cstdlib>で定義されており、引数として渡した文字列をシェルコマンドとして実行してくれます。クリアに使うコマンドはOSによって異なります。Linux / macOS:POSIX環境で動作する「clear」コマンドを使用Windows:コマンドプロンプト用の「cls」コマンドを使用Linuxでコンソールをクリアするサンプルコード以下は、Linux環境で「clear」コマンドをsystem()関数に渡

  2. ファーミング(Pharming)とは?その仕組みと効果的な対策方法を徹底解説

    現代では、安易に騙されるコンピューターユーザーは少なくなりました。インターネット上でマルウェアに関する教育が広く行き渡ったおかげで、「数百万ドル当選」などを謳う詐欺メールに簡単に引っかかる人は減っています。 しかし、それでハッカーたちの手口がなくなったわけではありません。むしろ、彼らはより巧妙な方法へとシフトしています。企業インフラを盗み見して上司のアドレスから従業員にメールを送ったり、ユーザーのFacebookアカウントを乗っ取って友人にメッセージを送ったりするなど、現在のハッキングでは「信頼の悪用」が主流の手口となっています。 そんな手口の一つに、正規のURLから偽サイトへアクセスを迂回