5

私はテストのために勉強しています、そして私はこれらのどれかがfree(ptr)と同等であるかどうか疑問に思いました:

 malloc(NULL); 

 calloc(ptr); 

 realloc(NULL, ptr); 

 calloc(ptr, 0); 

 realloc(ptr, 0);

私が理解していることから、free()関数は、ptrの後のメモリが再び使用可能になったことをCに実際に通知するため、これらはいずれも機能しません。申し訳ありませんが、これはちょっとした質問ですが、助けていただければ幸いです。

4

3 に答える 3

14

実際、それらの最後のものは への呼び出しと同等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()

于 2009-04-15T02:25:09.243 に答える
4
realloc(ptr, 0);

と同等ですfree(ptr);(ただし、そのような使用はお勧めしません!)

また、これら2つの呼び出しは互いに同等です(ただし、無料ではありません)。

realloc(NULL,size)
malloc(size)
于 2009-04-15T02:21:22.277 に答える
0

最後のものrealloc(ptr, 0)---終わります。割り当てられたブロックを解放し、最小限の割り当てに置き換えます(私のMac OS X 10.5マンページによると)。ローカルのマンページをチェックして、システムで何が行われるかを確認してください。

つまりptr、実質的なオブジェクトを指すと、そのメモリのほとんどを取り戻すことができます。


Debian LennyのmanページはMitchJonathanに同意しています...BSDはこれに関してLinuxから本当に分岐していますか?


問題のあるマニュアルページから:

realloc()関数は、ptrが指す割り当てのサイズをsizeに変更しようとし、ptrを返します。[...]サイズがゼロでptrがNULLでない場合、新しい最小サイズのオブジェクトが割り当てられ、元のオブジェクトが解放されます。


Linuxとsolarisのマニュアルページは非常にクリーンで、'89標準:realloc(ptr,0)のように機能しfree(ptr)ます。上記のMacOSのマンページ、およびJonathanが引用した標準はあまり明確ではありませんが、同等性を破る余地があるようです。

なぜ違いがあるのか​​疑問に思っていました。「自由な行動」の解釈は私には非常に自然に思えます。私がアクセスできる両方の実装には環境変数駆動の調整可能性が含まれていますが、BSDバージョンはさらに多くのオプションを受け入れます。いくつかの例:

 MallocGuardEdges             If set, add a guard page before and after
                              each large block.  
 MallocDoNotProtectPrelude    If set, do not add a guard page before large
                              blocks, even if the MallocGuardEdges envi-
                              ronment variable is set.

 MallocDoNotProtectPostlude   If set, do not add a guard page after large
                              blocks, even if the MallocGuardEdges envi-
                              ronment variable is set.

 MallocPreScribble            If set, fill memory that has been allocated
                              with 0xaa bytes.  This increases the likeli-
                              hood that a program making assumptions about
                              the contents of freshly allocated memory
                              will fail.
 MallocScribble               If set, fill memory that has been deallo-
                              cated with 0x55 bytes.  This increases the
                              likelihood that a program will fail due to
                              accessing memory that is no longer allo-
                              cated.

freeおそらく、「最小サイズのオブジェクト」は、通常モードでは何もありません(つまり、同等です)が、いくつのガードが配置されているものです。それが価値があるもののためにそれを取りなさい。

于 2009-04-15T02:22:25.333 に答える