実際、それらの最後のものは への呼び出しと同等free()です。の仕様を注意深く読むrealloc()と、データを新たに割り当てたり、割り当てのサイズを変更したり (特に、新しいサイズが古いサイズよりも大きい場合、データを移動する可能性があります)、メモリを解放したりできることがわかります。それも。実際、他の関数は必要ありません。それらはすべて の観点から書くことができますrealloc()。正気の人間がそうするわけではありませんが、それは可能です。
関数ファミリーの危険性の完全な分析については、Steve Maguire の「Writing Solid Code 」を参照してください。「Writing Solid Code」を読むことの危険性を完全に分析するには、 ACCUmalloc()の Web サイトを参照してください。レビューが示すほど悪いとは思いませんが、治療が完全に欠けていることは確かです(C89がまだ新しく、完全に実装されていなかった90年代初頭までさかのぼります)。const
MacOS X 10.5 (BSD) に関する D McKee のメモは興味深い...
C99 標準は次のように述べています。
7.20.3.3 malloc 関数
あらすじ
#include <stdlib.h>
void *malloc(size_t size);
説明
malloc 関数は、サイズが size で指定され、値が不定であるオブジェクトにスペースを割り当てます。
戻り値
malloc 関数は、ヌル ポインターまたは割り当てられた領域へのポインターを返します。
7.20.3.4 realloc 関数
あらすじ
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
説明
realloc 関数は、ptr が指す古いオブジェクトの割り当てを解除し、size で指定されたサイズを持つ新しいオブジェクトへのポインターを返します。新しいオブジェクトの内容は、新しいサイズと古いサイズの小さい方まで、割り当て解除前の古いオブジェクトの内容と同じでなければなりません。古いオブジェクトのサイズを超える新しいオブジェクトのバイトは、不確定な値を持ちます。
ptr がヌル ポインターの場合、realloc 関数は、指定されたサイズに対して malloc 関数のように動作します。それ以外の場合、ptr が calloc、malloc、または realloc 関数によって以前に返されたポインターと一致しない場合、または空間が free または realloc 関数の呼び出しによって解放された場合、動作は未定義です。新しいオブジェクトのメモリを割り当てることができない場合、古いオブジェクトは割り当て解除されず、その値は変更されません。
戻り値
realloc 関数は、新しいオブジェクトへのポインター (古いオブジェクトへのポインターと同じ値を持つ可能性があります) を返すか、新しいオブジェクトを割り当てることができなかった場合は null ポインターを返します。
追加のヘッダーと関数による編集上の変更は別として、ISO/IEC 9899:2011 標準は C99 と同じことを述べていますが、セクション 7.20.3 ではなく 7.22.3 です。
realloc の Solaris 10 (SPARC) man ページには次のように書かれています。
realloc() 関数は、ブロック ポインターのサイズを ptr によって size バイトに変更し、(おそらく移動された) ブロックへのポインターを返します。新旧サイズの小さい方まで中身は変わりません。ブロックの新しいサイズがブロックの移動を必要とする場合、ブロックの以前のインスタンス化のためのスペースが解放されます。新しいサイズがより大きい場合、ブロックの新しく割り当てられた部分の内容は未規定です。ptr が NULL の場合、realloc() は、指定されたサイズに対して malloc() のように動作します。size が 0 で、ptr が NULL ポインターでない場合、ポイントされたスペースは解放されます。
これはかなり明示的な「free() のように機能する」ステートメントです。
しかし、MacOS X 10.5 や BSD が別のことを言っているということは、私の最初の段落の「正気な人はいない」という部分を再確認するものです。
もちろん、C99 Rationaleがあります ...それは言う:
7.20.3 メモリ管理機能
これらの関数の定義における null ポインターと長さゼロの割り当て要求の処理は、このパラダイムをサポートしたいという願望によって部分的に導かれました。
OBJ * p; // pointer to a variable list of OBJs
/* initial allocation */
p = (OBJ *) calloc(0, sizeof(OBJ));
/* ... */
/* reallocations until size settles */
while(1) {
p = (OBJ *) realloc((void *)p, c * sizeof(OBJ));
/* change value of c or break out of loop */
}
このコーディング スタイルは、必ずしも委員会によって承認されているわけではありませんが、広く使用されていると報告されています。
一部の実装では、0 バイトの割り当て要求に対して null 以外の値が返されました。この戦略には、「何もない」と「ゼロ」 (未割り当てのポインターと長さ 0 の空間へのポインター) を区別するという理論上の利点がありますが、長さ 0 のオブジェクトの概念を必要とするという、より説得力のある理論上の欠点があります。そのようなオブジェクトは宣言できないため、それらが存在する唯一の方法は、そのような割り当て要求を介することです。
C89 委員会は、長さゼロのオブジェクトのアイデアを受け入れないことを決定しました。したがって、割り当て関数は、0 バイトの割り当て要求に対して null ポインターを返す場合があります。この処理は、上記のパラダイムを排除しないことに注意してください。
C89の静かな変化
null 以外のポインターを返すサイズ 0 の割り当て要求に依存するプログラムは、動作が異なります。
[...]
7.20.3.4 realloc 関数
null の最初の引数は許容されます。最初の引数が null ではなく、2 番目の引数が 0 の場合、呼び出しは最初の引数が指すメモリを解放し、null 引数が返される場合があります。C99 は、サイズがゼロのオブジェクトを許可しないというポリシーと一致しています。
C99 の新機能: realloc 関数が変更され、ポイント先のオブジェクトの割り当てが解除され、新しいオブジェクトが割り当てられ、新しいオブジェクトの内容が古いオブジェクトの内容と同じであることが明確になりました。 2つのサイズの。C89 は、新しいオブジェクトが古いオブジェクトと同じオブジェクトであるが、異なるアドレスを持つ可能性があることを指定しようとしました。これは、オブジェクトのアドレスが存続期間中一定であると想定する標準の他の部分と矛盾します。また、サイズがゼロの場合に実際の割り当てをサポートする実装は、この場合に必ずしも null ポインターを返すとは限りません。C89 は null の戻り値を必要とするように見え、委員会はこれは制限が厳しすぎると感じました。
Thomas Padron-McCarthy は次のように述べています。
C89 では、「サイズがゼロで、ptr が null ポインターでない場合、それが指すオブジェクトは解放される」と明示的に述べられています。それで、彼らはC99でその文を削除したようですか?
はい、冒頭の文に含まれているため、彼らはその文を削除しました。
realloc 関数は、ptr が指す古いオブジェクトの割り当てを解除します
そこには蠢く余地はありません。古いオブジェクトの割り当てが解除されます。要求されたサイズがゼロの場合、返される可能性のあるものは何でも返されます。これは多くの場合 (通常は) null ポインターですが、返される可能性があるが正当に逆参照できないmalloc(0)非 null ポインターである可能性があります。free()