[解決済み] 添え字で最後から1つ後ろの配列要素のアドレスを取得する:C++標準では合法かどうか?
質問
以下のコードは 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を参照する (を参照します(私が見る限り、これは合法です。 で、結果は "配列の要素タイプの無関係なオブジェクト という結果になります。 となります)、そしてその要素のアドレスを取ります。 その要素のアドレスを取得します。 は十分に合法であると思われます。
この場合、最終的な結果は同じですが、全く同じことをするわけではありません。
関連
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] なぜGCCは、速度の代わりにサイズに最適化すると、15-20%速いコードを生成するのですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】int a[] = {1,2,}; なぜイニシャライザーリストの最後のカンマは許されるのでしょうか?
-
[解決済み】CとC++におけるユニオンの目的
-
[解決済み] なぜ参照の配列は不正なのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】抽象クラス型の無効なnew-expression
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】オブジェクト引数のない非静的メンバ関数の呼び出し コンパイラーエラー
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み] ポインタの「デリファレンス」とはどういう意味ですか?