2011-07-21 13 views
-1

私はサイズ9.の配列を定義していますが、配列インデックス10にアクセスするとエラーは発生しません。なぜコンパイラは動的配列の境界を越えて要素にアクセスすることについて不平を言っていないのですか?

int main() { 
    bool* isSeedPos = new bool[9]; 
    isSeedPos[10] = true; 
} 

私の配列には配列要素isSeedPos[10]がないので、私は、コンパイラエラーを取得すると予想。

なぜエラーが発生しますか?

+3

この質問のタイトルを改善できますか?それは本当に問題をよく説明するものではありません。あなたの質問を他人と区別するタイトルをつけてみてください。 –

答えて

1

代わりにstd :: vectorを使用してください。デバッグモードで境界チェックを行う実装もあります。

0

問題ありません。アクセスしないでくださいメモリにアクセスしています。配列の後にメモリにアクセスできます。

+2

「配列の後のメモリ」ということはわかりません。あなたは未定義の振る舞いを呼び出しています。定義されたセマンティクスはありません。 –

0

これはJavaではありません。 CまたはC++では、境界チェックはありません。あなたはそのインデックスに書き込むことができる純粋な運です。

+1

彼のプログラムが運営することは運と何の関係もありません。それが "うまくいく"とすれば、それは_unlucky_だと思います。 –

+0

@Tomalak、ちょっと公正ではない、質問が変わった - 私が答えたので、大幅にOPがコンパイル時または実行時に何かを予期しているかどうかの表示がなかったので - 実行時を想定した。 (私の知る限り)。一般的なポイントはまだ有効ですが、興味深いことに、他の回答で複数回繰り返されています... – Nim

+0

この質問に対する多くの回答は、少しずつ誤解を招くものです。 –

1

いいえ、このケースでは、コンパイラは診断を発行する必要はありません。コンパイラは、境界チェックを実行しません

コンパイラは、エラーにエラーが発生しないため、このような壊れたコードを書き込まないようにするのはあなたの責任です。

1

javaやpythonのような他の言語とは異なり、配列アクセスはCやC++ではバウンドチェックされません。そのため、アレイへのアクセスが高速になります。あなたが境界内にいることを確認するのはあなたの責任です。

しかし、このような単純なケースでは、一部のコンパイラがコンパイル時にエラーを検出できます。

また、valgrindなどのツールを使用すると、実行時にこのようなエラーを検出するのに役立ちます。

1

どのコンパイラ/デバッガを使用していますか? MSVC++はそれについて文句を言って、配列の境界から書き出すことを伝えます。 しかし、それは標準で行う必要はありません。 いつでもクラッシュする可能性があり、未定義の動作が発生します。

+0

動的に割り当てられた配列です。それは文句を言うだろうか? –

+0

通常そうです。 MSVCを使用すると、デバッガにクラッシュする可能性があります。または、プログラムが終了するときにランダムなクラッシュを生成します。しかし、MSVCはそのようなものを検出するのにはかなり良いです。 –

+1

MSVCのように聞こえることはありません。あなたが幸運だったので、プログラムがクラッシュするように思えます。 –

1

プリミティブ配列は境界チェックを行いません。境界チェックが必要な場合は、代わりにstd :: vectorを使用する必要があります。あなたは配列の終わりの後に無効なメモリにアクセスしています。純粋にそれは動作しています。

0

isSeedPos配列の大きさはわかりません。これは、メモリ内の位置へのポインタに過ぎません。 isSeepPos[10]を指すと、動作は未定義です。クラッシュする必要はありません。確かに標準エラーチェックはありません。

1

メモリアクセスがc、plain、simpleでチェックされていることを示すルールはありません。 boolの配列を尋ねると、オペレーティングシステムが9bitのものではなく16bitの32bit配列を得る方が速いかもしれません。これは、あなたが誰かの宇宙空間に書いたり読んだりしていないかもしれないことを意味します。

C++は高速であり、高速である理由の1つは、あなたが何をしているかについてのチェックがほとんどないということです。プログラミング言語は、あなたがしていることを知っていると仮定しますオペレーティングシステムが不平を言っていなければ、すべてが実行されます。

5

これは問題ではありません。

C++配列にはバインドチェックがありません。配列の制限を超えて要素にアクセスすることはできます(ただし、通常はエラーが発生します)。

配列を使用する場合は、範囲外でないことを確認する必要があります(サイズを別の変数に保持することができます)。

もちろん、より良い解決策は、std::vectorのような標準ライブラリコンテナを使用することです。 std::vectorで あなたはどちらか

  • は(あなたが範囲外にある場合に例外をスローします)i番目の要素Cスタイルの配列と同じ構文で
  • 使用myVector[i]を取得するためにmyVector.at(i)メソッドを使用することができますが、各boolは、メモリの1ビットだけをとるように自分でチェックバインドしなければならない(例えば、それをアクセスする前にif (i < myVector.size()) ...を試してみてください)

はまた、あなたの場合には、std::vector<bool>が実装特殊なバージョンであることに注意してください(従って、それはboolの配列よりも少ないメモリを使います。これはあなたが望むかもしれないし、そうでないかもしれません)。

+0

'std :: vector'を使って境界を調べるには' operator [] 'を使うことはできません。 'at()'関数を使う必要があります。 –

+0

そして 'std ::'名前空間はSTLとは関係がありません! –

+0

@Martinho Fernandes:corrected - @Tomalak Geret'kal:STLコンテナと 'std ::'の名前空間の 'vector'はどちらも同じではありませんか? – Louen

1

インデックスにランタイムチェックがありません。要素10にアクセスするのは間違っていますが、可能です。

  • "不運"の場合、これはクラッシュせず、配列の後ろにあるデータを返します。
  • 「運が良ければ」配列の後のデータはプログラムによって割り当てられないため、要求されたアドレスへのアクセスは禁止されています。これはオペレーティングシステムによって検出され、「セグメント化エラー」を生成します。
+0

"配列の後ろにあるデータが返されます"とか、それ以外はどこかで返されます。あなたが不運になり、あなたのプログラムがクラッシュしていないからといって、明確に定義されたセマンティクスであなたのプログラムを突然動かすわけではありません。 –

+0

そのようなコードは、配列から書き出すときに未定義の動作を引き起こす可能性があります。バグを追跡するのが難しいかもしれません。 – neodelphi

+0

確かに、またはあなたの鼻腔にブラックホールが存在する可能性があります。 –

0

その位置に書き込むことは危険です。

コンパイラはあなたにそれをさせるでしょう - 効果的には、その配列に割り当てられたメモリの最後のバイト= 1を書いているのは良いことではありません。

C++は他の多くの言語によく似ていません - あなたはあなたが何をしているかを知っていると仮定しています!

0

CとC++の両方で、任意のメモリ領域に書き込むことができます。これは、もともと、メモリマップされた周辺機器などに正当に書きたい低レベルのプログラミングから派生したものであり、プログラマがすでにその値を知っているときに境界チェックを省略する方が効率的であるためです(例えば、配列上のループ0からNの場合、彼は0を知り、Nは境界内にあるので、各中間値をチェックするのは余分です)。

しかし、実際には、今日はめったにそれをしたくありません。 arr [i]構文を使用する場合は、arrで宣言された配列に書き込むことを基本とし、他に何もしないでください。しかし、あなたがしたい場合でもあなたはまだできます。

doあなたがこの場合のように任意のメモリに書き込むと、あなたのプログラムの一部になるか、またはあなたが知らないうちに他の重要なデータが変更されます。コードを変更して、あなたがしていたことを忘れてしまった)。またはあなたのプログラムに割り当てられていないメモリに書き込み、OSは悪い問題を防ぐためにOSをシャットダウンします。今日で

:あなたはあなたのプログラムが割り当てられていないメモリ

  • への書き込みを行うかどうかをテストしますツールがありますが、この1
  • のような明白なミスをした場合

    • 多くのコンパイラがそれを見つけるだろうあなたはして使用する必要がありますすることができますstd :: vectorの代わりに、境界チェックが必要な時間の99%があります。 (()または[]でアクセスしてください)
  • +0

    それを見つけ出すコンパイラは何ですか?そして、btw、C + +は、任意のメモリに書き込むことはできません。 –

    +0

    ありがとうございます。コンパイラのチェックに間違いがあるかもしれませんが、私は実際にはわかりませんでした。 C++はあなたが任意のメモリに書き込めるようにしていません。標準の保護されたオペレーティングシステムでプログラムを実行すると、書き込まれた言語が何であれ仮想メモリに書き込まれることを意味しますか?あるいは、あなたが望むものにポインタを割り当てたり、逆参照したりすることはできません。あるいは、0番地への書き込みは本当に面倒なことでしょうか?それとも何か私は愚かに行方不明だった? –

    +0

    私は、そういうようなコードを書いていても、コンパイラが実際にコンパイルするかもしれないが、C++では常に明確な場所に書き込む必要があるということを意味する。メモリ内の他の場所にデータを書き込もうとすると、未定義の動作になります。 –

    関連する問題