7

C の malloc 関数を把握しようとして、次のコードを書きました。

int i;

int *arr = (int*)malloc(5*sizeof(int)); 

if(arr==NULL){

  printf("Failed to allocate memory for arr...\n");
  exit(1);

}

これは、配列に追加できる要素が5つだけであることを意味すると思いました。それが本当かどうかをテストするために、次のコードを追加しました。

arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
arr[5] = 6;
arr[6] = 7;
arr[7] = 8;
arr[8] = 9;

for(i=0;i<9;i++){

    printf("%d\n",arr[i]);

}

驚いたことに、そのコードは完全にコンパイルされ、実行されました。それはどのように可能でしたか?

4

4 に答える 4

9

C は配列境界チェックを強制しないため、5 つの整数用のスペースを要求している間に、より多くのスペースを使用しました。

実際、特定の目的のために確保されていない 4 つのメモリ ロケーションを上書きしました。プログラムは、配列用に確保されたメモリ内の領域を通過し、割り当てられた領域外のメモリに値を格納し始めました。

これが「うまくいった」という事実は単なる運であり、依存するものではありません。次の 100 回は機能するか、次回の試行時に失敗する可能性があり、ほとんどの場合、「セグメンテーション違反」メッセージが表示されます。

malloc の戻り値を賢明にチェックすること、境界チェックの責任があることに注意すること、高い警告レベルを有効にしてコードをコンパイルすることなどによって行ったような防御的プログラミングは、この種のエラーを防ぐための最善の防御策の一部です。valgrindや lint タイプ チェッカーなどの他のツールも役立ちますが、最終的にはあなた次第です。

C の最大の強みの 1 つである、低レベルから高レベルまであらゆる種類のことを自由に実行できることは、IMO の最大の弱点の 1 つでもあります。Java が Volvo なら、C はおそらくフェラーリに似ていて、ときどきむらのある休憩があります :)

于 2012-07-18T22:48:49.413 に答える
0

コンピュータのメモリは基本的に順番に配置されます。あなたはあなたにその記憶の小さな断片を与えるように頼みmallocました-5intのために十分です。コンピュータには、長さ5の配列を割り当てるのに必要なメモリよりも確実に多くのメモリがあります。したがって、に書き込みまたは読み取りを行う場合arr[8]は、メモリ内の別の場所に書き込んでいます。

通常、最近のコンピュータには大量のメモリがあるため、おそらく使用されていない場所に書き込んでいます。ただし、場合によっては、他mallocのデータを誤って上書きしてしまうことがあります。

プログラムがクラッシュすることがあることに注意してください(予想どおり)。これは、割り当てられたメモリのはるか外側に書き込もうとして、アドレスが無効になる可能性があるためです。通常、OSはそれをキャッチし、プログラムをクラッシュさせます。

于 2012-07-18T22:52:43.517 に答える
0

C は境界チェックを行いません。

于 2012-07-18T22:49:31.730 に答える
0

それはどのように可能でしたか?

配列の末尾を超えて書いています。C には境界チェックがないため、これによってプログラムが (すぐに) クラッシュすることはありませんが、十分に長く書くと、最終的にはエラーが発生します。何百もの int 値を書き込める場合もあれば、余分な値を書き込めない場合もあります。

于 2012-07-18T22:49:40.737 に答える