0

動的に作成された配列のサイズを小さくするのに問題があります。私のmain関数は次のようになります。

int main(void) {
    // Intialize big array
    int * a = (int *)malloc(10*sizeof(int));
    assert(a);
    // Fill it with squares
    for (int i = 0; i < 10; ++i)
        a[i] = i*i;
    // Expected to print 64
    printf("%d\n", a[8]);
    // Shrink the big array
    int * b = (int *)realloc(a, 5*sizeof(int));
    assert(b);
    // Expected to cause SEGFAULT
    printf("%d\n", b[8]);
    return 0;
}

printf("%d\n", b[8]);行を除いてすべて64正常に動作しますが、期待どおりに SEGFAULT エラーは発生しません。なんで?

でメモリを縮小することに関連するSOの質問をたくさん見たので、単純なものが欠けていると思いますがrealloc、それらはすべて可能だと言っています。

GCC 4.8.2でUbuntu 14.04を使用し、-std=c99オプションでコンパイルしています。

4

4 に答える 4

8

b[8]2 番目のprintf呼び出しでは、割り当てられていないメモリにアクセスし、未定義の動作を呼び出します。それが基本的に未定義の動作の意味です。結果は予測できません。正常に動作しているように見えるかもしれませんが、次回はクラッシュする可能性があります。ここで考慮すべきことは他にもいくつかあります -

  • mallocメモリの割り当てに失敗する可能性があるため、assertマクロで戻り値をチェックするのは間違っています。assert範囲外の配列にアクセスするなど、不可能または間違ったコードをデバッグするために使用する必要があります。

  • の結果をキャストしないでくださいmallocmalloc の結果をキャストしますか?

  • reallocのようなメモリ ブロックの再割り当てに失敗する場合がありますmalloc。失敗するNULLと、古いブロックを変更せずに元に戻します。これは、古いメモリ ブロックのハンドルが失われ、リークが発生することを意味します。を呼び出す前に、古いブロックへのポインタを変数に格納する必要がありますrealloc

于 2014-05-14T06:36:19.893 に答える
5

未割り当て領域にアクセスしています。それは未定義の動作です。最悪の場合、今のように、まだ機能します。Segfault が発生する保証はありません。

于 2014-05-14T06:32:01.443 に答える
1

Realloc は、将来の malloc 操作に使用できる残りのバッファーをマークするだけです。それはUBです。そのバッファでmallocが発生しなかった場合でも、そのバッファにアクセスできます。それがあなたの場合です。未割り当てメモリへのアクセスで segfault が発生しないのは幸運です。

于 2014-05-14T06:35:46.210 に答える
1

アクセスしているメモリがプロセスに属しているかどうかに応じて、クラッシュするかどうかは未定義です。

int i;
int a[5];
for(i=0;i<10;i++)
  printf("%d\n", a[i]);

自分で確認する必要があります。

于 2014-05-14T06:36:08.570 に答える