9

この場合、reallocは失敗する可能性がありますか?

int *a = NULL;

a = calloc(100, sizeof(*a));
printf("1.ptr: %d\n", a);

a = realloc(a, 50 * sizeof(*a));
printf("2.ptr: %d\n", a);

if(a == NULL){
    printf("Is it possible?\n");
}

return (0);

}

私の場合の出力は次のとおりです。

1.ptr: 4072560
2.ptr: 4072560

したがって、「a」は同じアドレスを指します。では、reallocチェックを強制する必要がありますか?

後で編集

  • WindowsXPでのMinGWコンパイラの使用。
  • Linuxのgccと同様の動作ですか?

後で編集2:この方法で確認しても大丈夫ですか?

int *a = NULL, *b = NULL;

a = calloc(100, sizeof(*a));
b = realloc(a, 50 * sizeof(*a));

if(b == NULL){
    return a;
}
a = b;
return a;
4

6 に答える 6

7

はい、常にreallocのチェック、またはその他のメモリ割り当てを強制する必要があります。

同じアドレスを再利用する現在の動作は、信頼できない実装の詳細です。そうすることは、ライブラリがその実装を切り替えるか、新しいプラットフォームに移動するときに、バグに気付くだけです。

これは失敗する可能性がありますか?おそらくそうではないでしょう、あなたがそれがそうするケースを見つけることができれば私は驚かれることでしょう。しかし、それはそうではないという意味ではありません。すべての操作のチェックを自動的に実行する関数でreallocをラップするのは非常に簡単なので、実行しない理由はありません。

void* xrealloc(void* ptr, size_t size) {
  ptr = realloc(ptr, size);
  if ( !ptr ) {
    exit(EXIT_FAILURE);
  }
  return ptr;
}
于 2010-03-29T20:57:12.307 に答える
6

元の割り当てよりも小さいサイズが渡されたときに失敗した場合は驚くべきことですreallocが、C 標準 (7.20.3.4) では常に成功することを保証するものは何もありません。

realloc 関数は、 が指す古いオブジェクトの割り当てを解除し、ptrで指定されたサイズの新しいオブジェクトへのポインタを返しますsize。新しいオブジェクトの内容は、新しいサイズと古いサイズの小さい方まで、割り当て解除前の古いオブジェクトの内容と同じでなければなりません。古いオブジェクトのサイズを超える新しいオブジェクトのバイトの値は不定です。

ptrが null ポインターの場合、関数 は指定されたサイズrealloc の関数のように動作します。mallocそれ以外の場合、、、または関数ptrによって以前に返されたポインターと一致しない 場合、またはまたは関数の呼び出しによってスペースが割り当て解除された場合 、動作は未定義です。新しいオブジェクトのメモリを割り当てることができない場合、古いオブジェクトは割り当て解除されず、その値は変更されません。callocmallocreallocfreerealloc

戻り値

このrealloc関数は、新しいオブジェクトへのポインター (古いオブジェクトへのポインターと同じ値を持つ場合があります) を返すか、新しいオブジェクトを割り当てることができなかった場合は null ポインターを返します。

の非常に単純な適合実装は次のreallocようになります。

void *realloc(void *ptr, size_t size)
{
    void *new_ptr= malloc(size);
    if (new_ptr && ptr)
    {
        size_t original_size= _get_malloc_original_size(ptr);
        memcpy(new_ptr, ptr, min(original_size, size));
        free(ptr);
    }

    return new_ptr;
}

メモリ不足の状態 (またはmallocが返される条件NULL) では、これは を返しNULLます。

元の割り当てのサイズが要求されたサイズ以上の場合、同じポインターを返すことも非常に単純な最適化です。しかし、C 標準にはそれを指示するものは何もありません。

于 2010-03-29T21:22:24.723 に答える
2

いずれの場合もの戻り値を確認することreallocをお勧めします(メモリブロックを拡張するよりも縮小する方が安全であると仕様には記載されていません)。ただし、最初のポインタ(この場合はそうします)を失わないように注意する必要があります。そうすると、完全に解放できなくなります。

于 2010-03-29T20:59:06.547 に答える
2

C99 標準 §7.20.3.4 (realloc) は次のように述べています。

realloc 関数は、ptr が指す古いオブジェクトの割り当てを解除し、size で指定されたサイズを持つ新しいオブジェクトへのポインターを返します。新しいオブジェクトの内容は、新しいサイズと古いサイズの小さい方まで、割り当て解除前の古いオブジェクトの内容と同じでなければなりません。古いオブジェクトのサイズを超える新しいオブジェクトのバイトは、不確定な値を持ちます。

ptr がヌル ポインターの場合、realloc 関数は、指定されたサイズに対して malloc 関数のように動作します。それ以外の場合、ptr が calloc、malloc、または realloc 関数によって以前に返されたポインターと一致しない場合、または空間が free または realloc 関数の呼び出しによって解放された場合、動作は未定義です。新しいオブジェクトのメモリを割り当てることができない場合、古いオブジェクトは割り当て解除されず、その値は変更されません。

戻り値

realloc 関数は、新しいオブジェクトへのポインター (古いオブジェクトへのポインターと同じ値を持つ場合があります) を返すか、新しいオブジェクトを割り当てることができなかった場合は null ポインターを返します。

古いオブジェクトの割り当てが解除されることに注意してください。新しいオブジェクトたまたま古いオブジェクトと同じ場所を指している可能性があります。そして、問題が発生する可能性があります。可能性はかなり低いですが、奇妙な例外を設けるよりも、「常に」ルールを使用する方がはるかに簡単です。

通常の反論は、「これが失敗できない場合、テストできないエラーパスがあることを意味します」です。ある程度までは、それは本当です。ただし、制御情報が破損しているため、メモリが踏みにじられて割り当てが成功しない可能性があります。コア ダンプを取得する可能性が高くなりますが、コードはそれを回避できるほど堅牢である可能性があります。(ハードコードされた 100 と 50 は、質問をするためのものだと思います。実際のコードは、実際に必要な量がわかっている場合、過剰に割り当てません。)

ここのように「realloc()」への 2 つの呼び出しが隣接している場合、問題が発生する余地はほとんどありません。ただし、実際に動作するコードでは、2 つの間にいくつかの操作があり、そのコードによって 2 番目の「realloc()」が失敗する可能性があります。

あなたの「編集2」について...

コードは次のように記述したほうがよい場合があります。

if (b != NULL)
    a = b;
return a;

しかし、基本的なコンセプトはOKです。標準では、新しい割り当てを作成できない場合、元の割り当ては安全であると明示的に述べていることに注意してください。

于 2010-03-29T21:21:15.143 に答える
1

チェックにかかる時間は、realloc()で費やされる時間に比べて非常に短いため、なぜ問題になるのかさえわかりません。または、コードの行数を減らしたいですか?

于 2010-03-29T21:28:54.913 に答える
1

realloc()NULLサイズの縮小で十分に簡単に戻ることができます。

void *ptr = malloc(10);
ptr = realloc(ptr, 0);
if (ptr == NULL) {
  puts("Failure because return value is NULL? - not really");
}

realloc(any_pointer, 0)NULL返すか、または何らかのポインターを返すことができnot-NULLます。これは実装定義です。

そのため、realloc()/malloc()失敗は単純なテストではありませんがif (ptr == NULL)

void *ptr = malloc(newsize); // or realloc(..., newsize)
if (ptr == NULL && newsize > 0) {
  exit(0); // Handle OOM;
}

realloc()このあいまいさのため、コードでラッパーを作成する必要がある場合は、次のようなものをお勧めします。

void *xrealloc(void *ptr, size_t newsize, bool *falure) {
  *failure = 0;
  if (newsize > 0) {
    void *tmp = realloc(ptr, newsize);
    if (tmp == NULL) {
      *failure = 1;
      return ptr;  // old value
    }
    return tmp;  // new value
  } 
  free(ptr);
  return NULL; // new value
  }

したがって、サイズを縮小して取得することは実際には失敗ではないためNULLこの回答は接線的にのみ適用されますが、OPの質問は「...新しいブロックサイズが初期サイズよりも小さい場合、reallocチェックを強制しますか?」でした。そして、信頼性の低いパラダイムを使用しました。realloc()if (ptr == NULL)

于 2014-09-13T03:45:26.480 に答える