Man reallocから:realloc()関数は、新しく割り当てられたメモリへのポインタを返します。これは、あらゆる種類の変数に適切にアラインされ、多分 ptrとは異なります。要求が失敗した場合はNULLになります。
したがって、このコードスニペットでは:
ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){ //reallocated pointer ptr1
printf("Exiting!!\n");
free(ptr);
exit(0);
}else{
free(ptr); //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
ptr = ptr1; //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address
}
再割り当てされたポインターが同じブロックではなく、別のメモリブロックを指していると仮定するだけで十分ですか?仮定がfalseになり、reallocがptrが指す元のメモリブロックのアドレスを返し、次にfree(ptr)を返すためです(コメントで与えられた理由で)実行すると、メモリブロックが消去され、プログラムが異常終了します。 ptrとptr1の同等性を比較し、free(ptr)ステートメントの実行を除外する別の条件を設定する必要がありますか?
ハッピーパスの元のptrでfree()
を呼び出さないでください。基本的にrealloc()
がそれを行います。
ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{
printf("\nExiting!!");
free(ptr);
exit(0);
}
else
{
ptr = ptr1; // the reallocation succeeded, we can overwrite our original pointer now
}
以下の良いコメントに基づいて、修正を編集として適用します。
このcomp.lang.cの質問 を読むと、3つのケースが明らかになります。
realloc
が十分なスペースをまったく見つけられない場合、nullポインターを返し、前の領域を割り当てたままにします。」これは直接コードに変換できます:
_int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3, clean up then terminate.
free(ptr);
exit(0);
}
else if(tmp == ptr)
{
// Case 1: They point to the same place, so technically we can get away with
// doing nothing.
// Just to be safe, I'll assign NULL to tmp to avoid a dangling pointer.
tmp = NULL;
}
else
{
// Case 2: Now tmp is a different chunk of memory.
ptr = tmp;
tmp = NULL;
}
_
したがって、考えれば、投稿したコードは(ほぼ)正常です。上記のコードは次のように単純化されます。
_int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3.
free(ptr);
exit(0);
}
else if(ptr != tmp)
{
ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;
_
ptr
とtmp
は同じ場所を参照するため、else if(ptr != tmp)
を呼び出したくないケース1を除外する追加のfree(ptr)
に注意してください。また、安全のために、NULL
がスコープ内にあるときのぶら下がりポインタの問題を回避するために、tmp
をtmp
に割り当ててください。
OP:...はptrとは異なる場合があります。要求が失敗した場合はNULLになります。
A:常にではありません。 NULL
が0の場合、count
は正当に返される可能性があります(失敗ではありません)。
OP:再割り当てされたポインターが同じブロックではなく、別のメモリブロックを指していると想定するだけで十分です。
A:いいえ
OP:ptrとptr1の同等性を比較し、free(ptr)ステートメントの実行を除外する別の条件を設定する必要がありますか?
A:いいえ。
realloc()
がNULL
を返した場合(およびcountが0でない場合)、ptr
の値は引き続き有効であり、サイズ変更されていないデータを指しています。 free(ptr)
かどうかは、目標によって異なります。
realloc()
がNULL
を返さない場合、free(ptr)
を行わない場合、すべて解放されます。
例: https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper
#include <assert.h>
#include <stdlib.h>
int ReallocAndTest(char **Buf, size_t NewSize) {
assert(Buf);
void *NewBuf = realloc(*Buf, NewSize);
if ((NewBuf == NULL) && (NewSize > 0)) {
return 1; // return failure
}
*Buf = NewBuf;
return 0;
}
realloc
が指す実際のメモリチャンクを拡張するのに十分なスペースがある場合、ptr
は同じアドレスをptr
に返します。それ以外の場合は、データを新しいチャンクに移動し、古いチャンクを解放します。 ptr1
がptr
と異なることに依存することはできません。プログラムは未定義で動作します。
realloc
が別のアドレスを返す場合、最初に古いアドレスの割り当てを解除するので、自分で行う必要はありません。
ところで、malloc/realloc
:)の戻り値をキャストしないでください。コードは次のようになります。
ptr=malloc(sizeof(int));
ptr=realloc(ptr,count*sizeof(int));
if(ptr==NULL)
{
// error!
printf("\nExiting!!");
// no need to free, the process is exiting :)
exit(0);
}
realloc
がデータを移動する場合、バックグラウンドで古いポインタが解放されます。 C11標準のコピーはありませんが、C99標準では保証されています。
free
が成功した場合は、元のポインタrealloc
をしないでください。 free
が失敗した場合にそのポインタをrealloc
するかどうかは、特定のアプリケーションのニーズによって異なります。その追加メモリがないと絶対に続行できない場合、これは致命的なエラーとなり、保持されているストレージの割り当てを解除して終了します。 OTOH、それでも続行できる場合(おそらく別の操作を実行し、メモリが後で利用可能になることを期待している場合)、おそらくそのメモリを保持し、後で別のrealloc
を試行する必要があります。
章と節 :
7.22.3.5 realloc関数
あらすじ
1#include <stdlib.h> void *realloc(void *ptr, size_t size);
説明
2
realloc
関数 古いオブジェクトの割り当てを解除しますptr
によってポイントされ、size
によって指定されたサイズを持つ新しいオブジェクトへのポインターを返します。新しいオブジェクトの内容は、割り当て解除前の古いオブジェクトの内容と同じで、新しいサイズと古いサイズの小さい方までです。古いオブジェクトのサイズを超える新しいオブジェクトのバイトには、不確定な値があります。3
ptr
がNULLポインターの場合、realloc
関数は、指定されたサイズのmalloc
関数のように動作します。それ以外の場合、ptr
がメモリ管理関数によって以前に返されたポインタと一致しない場合、または領域がfree
またはrealloc
の呼び出しによって割り当て解除された場合、動作は未定義です。 新しいオブジェクトのメモリを割り当てることができない場合、古いオブジェクトは割り当て解除されず、その値は変更されません。戻り値
4
realloc
関数は、新しいオブジェクトへのポインター(古いオブジェクトへのポインターと同じ値を持つ場合があります)を返します。新しいオブジェクトを割り当てることができなかった場合は、nullポインターを返します。
強調が追加されました。条項4に注意してください。返されるポインタは、元のポインタと同じである可能性があります。