詳細 が述べたように、これは未定義の動作をもたらします。もう少し精度が続きます。
5.2.1/1 によると
[...] 式 E1[E2] は (定義により) *((E1)+(E2)) と同じです。
したがって、val[i]
と同等*((val)+i))
です。val
は配列であるため、加算が実行される前に配列からポインタへの変換 (4.2/1) が発生します。したがって、は に設定されている場所とval[i]
同等です。*(ptr + i)
ptr
int*
&val[0]
次に、5.7/2 は何ptr + i
を指すかを説明します。それはまた言います(強調は私のものです):
[...]ポインター オペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は undefinedです。
の場合ptr + i
、ptr はポインタ オペランドで、結果はptr + i
です。上記の引用によると、どちらも配列の要素または最後の要素の 1 つ後ろを指す必要があります。つまり、OP の場合ptr + i
は、すべての明確に定義された式ですi = 0, ..., 10
。最後に、 *(ptr + i)
は に対して明確に定義されていますが、 に対しては定義されて0 <= i < 10
いませんi = 10
。
編集:
val[10]
(または、同等に) が未定義の動作を生成するかどうかに困惑して*(ptr + 10)
います (C ではなく C++ を検討しています)。状況によってはこれが正しい場合 (int x = val[10];
未定義の動作など) もありますが、明確でない場合もあります。例えば、
int* p = &val[10];
これまで見てきたように、これはint* p = &*(ptr + 10);
未定義の動作 (の最後の要素の 1 つ前のポインターを逆参照するため) である可能性があるものと同等であるか、明確に定義さval
れているものと同じです。int* p = ptr + 10;
この質問がいかに曖昧であるかを示す次の 2 つの参考文献を見つけました。
配列の 1 つ後ろの要素のアドレスを取得できますか?
添え字を介して 1 つ後ろの配列要素のアドレスを取得する: C++ 標準で合法かどうか?