1. ホーム
  2. c++

[解決済み] 添え字で最後から1つ後ろの配列要素のアドレスを取得する:C++標準では合法かどうか?

2023-07-03 07:05:21

質問

以下のコードは C++ 標準では許可されていないと主張するのを何度か目にしました。

int array[5];
int *array_begin = &array[0];
int *array_end = &array[5];

&array[5] はこの文脈では合法的なC++コードですか?

可能であれば、標準への参照を伴う回答が欲しいです。

また、Cの標準を満たしているかどうかも知りたいところです。 そして、もしそれが標準 C++ でないなら、なぜそれを array + 5 または &array[4] + 1 ?

どのように解決するのですか?

あなたの例は合法ですが、実際には境界外ポインタを使用していないためです。

最初にアウトオブバウンズポインタに対処しましょう (例では代わりに one-past-the-end ポインタを使用していることに気づく前に、それが私が最初にあなたの質問を解釈した方法だったからです)。

一般に、あなたは を作成することはできません。 を作成することもできません。ポインタは配列内の要素を指していなければなりません。 末尾を1つ過ぎた . それ以外の場所はありません。

ポインタの存在すら許されないということは、明らかにそれを参照解除することも許されないということです。

以下は、この件に関して標準が述べていることです。

5.7:5:

積分型である式が 型に加算または減算されるとき ポインタのオペランドに加算または減算された場合、結果は ポインタのオペランドの型になります。ポインタ オペランドが配列オブジェクトの要素を指していて 配列オブジェクトの要素を指し、その配列が十分な大きさである場合 が十分に大きい場合、結果は を指す。 の差のような、元の要素からオフセットされた要素を指す。 との添え字の差が の添え字の差が と等しくなります。言い換えれば 式Pが配列オブジェクトのi番目の要素を指している場合 の要素を指す場合 式 (P)+N (等価に, N+(P))および(P)-N(Nは値n)を指します。 は値 n を持つ)は,それぞれ のi+n番目とi-n番目の要素を指す。 を指します。 さらに,式Pが配列の最後の要素を指す場合 が配列オブジェクトの最後の要素を指す場合 さらに,式Pが配列オブジェクトの最後の要素を指す場合,式(P)+1 は を指し,式(P)+1がその配列オブジェクトの最後の要素の1つ前を指し を指し、式Qが が配列オブジェクトの最後の要素を指すなら を指す場合は、式(Q)-1がその最後の要素を指します。 を指し示し、式(Q)-1 は配列オブジェクトの最後の要素を指し示します。 ポインタ・オペランドと結果の両方が同じ要素を指す場合 ポインタ・オペランドと結果の両方が同じ ポインタ・オペランドと結果の両方が同じ配列オブジェクトの要素を指す場合、 または最後の要素を1つ過ぎた 配列オブジェクトの最後の要素を指す場合、その評価は は,オーバーフローを発生させてはならない。 オーバーフローを発生させない。 それ以外の場合、動作は 未定義 .

(強調)

もちろん、これはoperator+の場合です。そこで念のため、配列の添え字について規格に書いてあることを紹介します。

5.2.1:1:

式は E1[E2] とは(定義上)同じです。 *((E1)+(E2))

もちろん、明らかな注意点があります。あなたの例は実際には境界外ポインタを示していません。このポインタが存在することは許されていますが(上記の通り)、私が見た限りでは、標準ではこのポインタの再参照については何も言っていません。私が見つけることができる最も近いものは 3.9.2:3 です。

[注:例えば、配列の末尾を1つ過ぎたアドレス(5.7)は、配列の無関係なオブジェクトを指すとみなされるでしょう。 そのアドレスにあるかもしれない、配列の要素型の無関係なオブジェクトを指すと考えられます。-注を終了する ]。

これは、はい、合法的にそれを参照解除することができますが、その場所への読み取りまたは書き込みの結果は不特定であることを意味するようです。

ilproxyil さんのおかげで、ここでの最後の部分を修正し、質問の最後の部分に答えることができました。

  • array + 5 は実際には 何も参照せず、単に を過ぎたものへのポインタを作成します。 の array .
  • &array[4] + 1 デリファレンス array+4 を参照します(これは完全に安全です)。 そのlvalueのアドレスを取得し そのアドレスに1を足すと その結果、最後から1つ前のポインタが生成されます。 (になります(ただし、このポインタは決して が参照されることはありません。
  • &array[5] 配列+5を参照する (を参照します(私が見る限り、これは合法です。 で、結果は "配列の要素タイプの無関係なオブジェクト という結果になります。 となります)、そしてその要素のアドレスを取ります。 その要素のアドレスを取得します。 は十分に合法であると思われます。

この場合、最終的な結果は同じですが、全く同じことをするわけではありません。