元の配列へのポインターを使用してそれを渡すように常に言われてきました。
元の配列の要素へのポインターを使用するように言われました。これは、配列を値で受け取る関数を宣言しようとすると、要素の型へのポインターを受け取るようにパラメーターの型を「調整」するように言語が指定するためです (事実上、配列のパラメーターの型がそのサイズを忘れてしまいます)。値ではなく参照によって渡されます)。したがって、基本的には、ソース コードが実際の真実を正確かつ明示的に表すように、手動で調整を行うように指示されています。
表示する宣言は、次のアドバイスを使用して宣言することもできます。
static void SceneMeshInitIndices(GLushort *meshIndices);
static void SceneMeshUpdateNormals(SceneMeshVertex (*mesh)[NUM_MESH_ROWS]);
static void SceneMeshUpdateMeshWithDefaultPositions(SceneMeshVertex (*mesh)[NUM_MESH_ROWS]);
int [X][Y]
の型が「Y int の X 配列の配列」を意味することは明らかです。したがって、要素の型は「Y int の配列」です。したがって、調整された型は「int (*)[Y]」または「Y int の配列へのポインター」です。
パラメータの型を「調整」するルールは、未加工の配列がひどい理由の 1 つであり、回避できる場合は使用すべきではありません。残念ながら、C にはそれを行う良い方法がありませんが、C++ には がstd::array
あり、配列が本来あるべき動作をします。つまり、値で渡すことができ、値で返すことができ、要素の型へのポインターに自動的に変換されることはありません (そのため、サイズを忘れることはありません) などです。
たぶん、より多くの例がそれをより明確にするでしょう。あなたが書いた場合:
void foo(int param[10]);
また、パラメーターの型を調整するルールを知らなかった場合は、次のコードでエラーが発生すると予想される場合があります。
int bar[5];
foo(bar); // error? an array of 5 ints is not the expected type.
そして、このコードの場合:
int baz[10];
foo(baz);
bar
配列がパラメーターにコピーされ、パラメーターに対して行われた変更が元の配列に影響を与えないことが予想される場合があります。残念ながら、これらの完全に合理的な期待は間違っています。あなたが書いvoid foo(int param[10]);
たとき、コンパイラは配列型のパラメータを見て、あなたが書いたのと同じになるようにそれを変更しますvoid foo(int *param);
したがって、あなたが書いfoo(bar)
たとき、コンパイラは関数がint*
(int[10]
あなたが書いた ではなく) を取ることを見て、それが に変換できることを見てbar
、int *
エラーを報告する代わりに、悪意を持って関数を呼び出すプログラムを生成します。記述した型が渡された変数と互換性がなくても、 の本体が次のfoo()
ようなことを実行できてもparam[9] *= 2;
、これが適切に定義されていることを保証する必要があります。
同様に、foo(baz)
は配列を値渡しせず、関数内の配列パラメーターに対して行われることはすべて、実際の配列に対して直接行われます。これは、すべてが値/コピーによって渡される通常の C セマンティクスとはまったく異なり、「参照渡し」の唯一の方法は、別のオブジェクトへの参照として機能するポインター値を取得することです。この場合、コンパイラはユーザーに代わってポインタを自動的に取得し、参照によって配列を効果的に渡します。
void foo(int [10])
さらに、書くかどうかvoid foo(int [100])
は問題ではないことに注意してください。どちらの場合も、パラメーターの型が調整されint *
ているため、それらの宣言は異なっているように見えますが、同じ関数を宣言しています。