簡単に言うと、本質的な違いは次のとおりです。 変数名はメモリ領域の名前であり、実行時には名前がありません。a と p はソース コードとコンパイル時にのみ意味を持ちます。 a という名前のメモリは、5 つの int を持つ int[5] 型のメモリです。 p は、int 型の int ポインターを 1 つだけ持つメモリ空間と名付けられます。 a[2] は、コンパイル中にそのメモリ空間の 3 番目のユニットに直接変換されます。 p[2] を p に変換し、int* メモリ空間の値を取り出し、2 を加算してメモリ空間のメモリ アドレスを取得します。 int const p は、p が指すメモリ空間を、不変の int ポインターを 1 つだけ持つように制限するだけです。
配列とポインタには 2 つのタイプがあります。
配列名は、最初の要素へのポインターに暗黙的に変換できます。
a
の型はint[5]
であり、sizeof(a)
はsizeof(int[5])
ではなくsizeof(int *)
と同等です。配列ポインタと通常のポインタの間には依然として違いがあります。結局のところ、配列が定義されると、その要素の型と番号が決定されます。
コンパイラが配列なのか通常のポインタなのかを推論できない場合に限り、通常のポインタのサイズに基づいて計算されます。
sizeof
たとえば、関数宣言では
void f(int* a)
となります。パラメータa
として任意のポインタを渡すことができます。入力すると、それが配列であるかどうかをコンパイラが推測することは不可能なので、
sizeof(a) = sizeof(int*)
しかし、あなたの質問の場合、コンパイラは
a
が 5 要素の整数配列であることを明確に推測できるため、sizeof(a) = sizeof(int[5])
簡単に言うと、本質的な違いは次のとおりです。
変数名はメモリ領域の名前であり、実行時には名前がありません。a と p はソース コードとコンパイル時にのみ意味を持ちます。
a という名前のメモリは、5 つの int を持つ int[5] 型のメモリです。
p は、int 型の int ポインターを 1 つだけ持つメモリ空間と名付けられます。
a[2] は、コンパイル中にそのメモリ空間の 3 番目のユニットに直接変換されます。
p[2] を p に変換し、int* メモリ空間の値を取り出し、2 を加算してメモリ空間のメモリ アドレスを取得します。
int const p は、p が指すメモリ空間を、不変の int ポインターを 1 つだけ持つように制限するだけです。