C++におけるsizeof
の理解: なぜn
は8
にならないのか?
C++で配列を扱う際、sizeof
演算子に関連して予期しない結果に遭遇することがあります。特に、配列を関数に渡すときにはその傾向が顕著です。本記事では、関数のパラメーターとしてsizeof
を使用する際に生じる一般的な混乱を探求し、特に以下の質問に答えます: なぜ関数foo()
内のn
は8
にならないのか?
問題
この問題を示す2つのコード例を見てみましょう。
例1: 関数foo()
void foo(char cvalue[8])
{
int n = sizeof(cvalue);
}
上記の例では、sizeof(cvalue)
を呼ぶと、n
が8
と等しいことを期待するかもしれません。配列はサイズ8
で定義されているからです。しかし、実際にはそうではありません。
例2: 関数bar()
void bar()
{
char cvalue[8];
int n = sizeof(cvalue);
}
この2つ目の例では、sizeof(cvalue)
は確かに8
に等しくなります。では、なぜ違いが生じるのでしょうか?
概念の理解
sizeof(cvalue)
がそれぞれの関数で異なる値を返す理由を理解するためには、CとC++における配列の扱いについて明確にする必要があります。
関数パラメーターとしての配列
CやC++で配列を関数に渡すとき、実際には配列そのものを渡しているわけではありません。代わりに、渡されるのは配列の最初の要素へのポインタです。関数パラメーターで使用されるブラケットは単なる構文の記法であり、動作を変えるものではありません。以下の2つの宣言は同等です:
void foo(char cvalue[8])
void foo(char cvalue[])
void foo(char *cvalue)
これらの宣言すべてにおいて、cvalue
はポインタとして解釈されます。したがって、foo()
内でsizeof(cvalue)
を呼び出すと、それは配列のサイズではなくポインタのサイズを返します。ほとんどのプラットフォームでは、このサイズは32ビットシステムで通常4
バイト、64ビットシステムで通常8
バイトであるため、foo()
内のn
は8
になりません。
bar()
における正しいコンテキスト
対照的に、bar()
内では、cvalue
がサイズ8
のローカル配列として定義されています。したがって、ここでsizeof(cvalue)
が呼ばれると、配列全体のサイズが正確に反映され、n
は8
になります。
重要なポイント
- ポインタの動作を理解する: 配列をパラメータとして渡すと、実際にはポインタを渡しており、
sizeof
を使用すると誤解を招く値になることがあります。 - ローカル配列:
sizeof
は関数内で定義されたローカル配列の実際のサイズを返し、期待される出力を提供します。 - 構文糖: 関数のパラメーター内のブラケットは配列変数を作成するのではなく、ポインタを扱っていることを示しています。
結論
CとC++で配列を扱うことは難解であり、特に言語に不慣れな人にとってはそうです。ポインタと配列の違いを理解することは、正確な計算とデバッグには重要です。関数内では、配列と見なされているパラメータにsizeof
を適用すると、意図した配列のサイズではなくポインタのサイズが返されることを覚えておいてください。
この説明が、関数内の配列引数に関連するsizeof
演算子の動作についての理解を深め、なぜfoo()
内でn
が8
とならず、bar()
内ではそうなるのかを明確にする手助けになれば幸いです。コーディングの際はこれらの原則を心に留めておいてください!