4

以下のコードに関して、スタックとヒープの違いを教えてください

int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
    arr [3000] = 8 ; //SIGSEGV 

    a = malloc (sizeof (int));
    a[4] = 6; 
    a[4000] = 8; //No error
}

arrは静的配列であり、arr [3000]を実行すると、他のプロセスのアドレスにアクセスしているため、SIGSEGVエラーが発生します。しかし、なぜa[4000]で実行時エラー(SIGSEGV信号)が発生しないのかわかりません。

ありがとう

4

6 に答える 6

9

これらの呼び出しのいずれかが実際にアクセスできないメモリに書き込むことは保証されていません(これによりセグメンテーションフォールトがトリガーされます)。プログラムがそのメモリに書き込む権限を持っていて、セグメンテーションフォールトをトリガーしない可能性もありますが、アレイに関係のない他の内部データを上書きします。もちろん、これはプログラムの他の場所で予期しない影響をもたらす可能性があります。

一般に、これは未定義動作と呼ばれます。配列の範囲外に書き込んだときに何が起こるかについての約束はありません。何かが起こるかもしれないし、起こらないかもしれません。

于 2012-01-23T18:47:57.997 に答える
3

配列の境界外の項目を参照することは未定義の動作です。つまり、何かが発生する可能性があります(例外、例外なし、またはその他)。arr[5]割り当てによってエラーが発生しなかった理由は、値がまだ有効なスタックスペース内にあったためである可能性があります(ただし、実行時間の長いアプリケーションでは、後でエラーが発生する可能性があります)。割り当てられた配列への無効な割り当てにより、プロセスに属するメモリ内のページへの書き込みが発生し、エラーが発生しなかった可能性があります。しかし、それは実行ごとに変わる可能性があります。また、アドレスがプロセスのアドレス空間外のページに属していたとしても、実際に何が起こるかはOSによって異なります。

于 2012-01-23T18:45:16.390 に答える
1

強調表示したすべてのケースは、「未定義動作」を表しています。

また、それが問題である場合もあれば、セグメンテーション違反である場合もあります。

「未定義動作」の特に悪い点は、しばらくの間は期待どおりに機能する可能性があるが、その後突然「望ましくない副作用」(つまり、セグメンテーション違反)が発生し始めることです。これにより、これらの条件を本番環境でデバッグおよび再現することが非常に困難になります。

于 2012-01-23T18:46:40.707 に答える
1
int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
// J: False - it is undefined. expect raptors, or something.

    arr [3000] = 8 ; //SEGSEV
// J: Now you see the effects of undefined behavior, even though you did not in a previous invalid access.

    a = malloc (sizeof (int));
    a[4] = 6; // J: Still undefined behavior
    a[4000] = 8; //No error
// J: Still undefined behavior
}

しかし、なぜa[4000]で実行時エラーが発生しないのかわかりません。segsev信号。

別のプラットフォームまたはアーキテクチャで実行されます。これは実際には問題ではありません。常にUBを回避する必要があります。

いずれにせよ、違いはシステムのアロケータの実装にあります(コンパイラがmallocの結果をスタックに配置しなかったと仮定します)。

アロケータがメモリを管理および分散する方法は、特にUBを使用する場合は、信頼してはならない実装の詳細です。

アロケータは、より大きな物理的割り当てからメモリの一部を販売できます。この基盤となる実装は、プラットフォームによって異なります。

于 2012-01-23T18:49:16.693 に答える
1

ヒープは、メモリのブロックをmalloc()する元のメモリです。

a [4000] = 8; 他のプロセスのメモリアドレスに分類されなかったのは幸運だったので失敗しませんでした。たまたまだった

于 2012-01-23T18:42:52.100 に答える
1

バッファオーバーフローは未定義の動作です。バッファオーバーフローは、スタック上にある場合は月曜日にクラッシュし、ヒープ上にある場合はTuedsayでクラッシュする可能性があります。それらは未定義の動作です。

これは、未定義の動作であると言うC段落です。

(C99、6.5.6p8)「結果が配列オブジェクトの最後の要素の1つ過ぎを指している場合、評価される単項*演算子のオペランドとして使用されないものとします。」

そしてもちろん、a[]は偽装単項演算*子です。

(6.5.2.1p2)「添え字演算子[]の定義は、E1 [E2]が(*((E1)+(E2)))と同一であるということです。」

于 2012-01-23T18:52:49.390 に答える