Code Fix

中級

配列と、先頭要素へのポインタでsizeofの結果が変わってしまう理由

配列そのもの(nums)と、先頭要素のアドレス(&nums[0])を混同してsizeofに渡してしまうバグです。見た目は似ていますが、前者は配列全体のバイト数、後者はポインタ1個分のサイズを返します。

なぜエラーが出ないのか

出力: 8
(エラーなし)
C++は何も報告しません。コンパイルも実行も正常に完了するためです
出力: 8
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  #include <iostream>
 2  int main() {
 3      int nums[5] = {1,2,3,4,5};
 4      std::cout << sizeof(&nums[0]) << std::endl;
                                ^
 5      return 0;
 6  }
出力: 8期待: 20(int5個分)

&nums[0]は「先頭要素へのポインタ」という別の型を作ってしまい、sizeofはポインタ自体のサイズ(8バイト)を返します。配列全体のサイズを知りたいときは配列名(nums)をそのまま渡します。

直し方: &nums[0]nums にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  #include <iostream>
 2  int main() {
 3      int values[10] = {0,1,2,3,4,5,6,7,8,9};
 4      std::cout << sizeof(&values[0]) << std::endl;
                                 ^
 5      return 0;
 6  }
出力: 8期待: 40(int10個分)

配列を関数に渡すときも同じ理由でポインタに変わってしまいます(配列のポインタへの減衰)。見た目は似ていても配列名とポインタは別の型情報を持ちます。

直し方: &values[0]values にします。

この問題を解いてみる →

パターン3

 1  #include <iostream>
 2  int main() {
 3      int data[3] = {1,2,3};
 4      std::cout << sizeof(&data[0]) << std::endl;
                                ^
 5      return 0;
 6  }
出力: 8期待: 12(int3個分)

&data[0]とdataはどちらも同じアドレスを指しますが、sizeofが見ているのは値ではなく型なので結果が変わります。

直し方: &data[0]data にします。

この問題を解いてみる →

よくある誤解

「配列名も&要素も結局は同じアドレスを指しているから同じ」というのは誤解です。配列名(nums)は「配列全体」という型情報を保ったままsizeofに渡りますが、&nums[0]は明示的に「int1個へのポインタ」という別の型を作ってしまいます。C++では配列を関数の引数として渡すときも同じ理由でポインタに変わってしまいます(配列のポインタへの減衰)。

まとめ

配列と、先頭要素へのポインタでsizeofの結果が変わってしまう理由は中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)