仕様によると、 malloc(0) は、「nullポインターまたはfree()に正常に渡すことができる一意のポインター」を返します。
これにより基本的に何も割り当てられませんが、心配せずに「アーティスト」変数をfree()の呼び出しに渡します。実用的な目的では、次のこととほとんど同じです。
artist = NULL;
C規格(C17 7.22.3/1)は次のように述べています:
要求されたスペースのサイズがゼロの場合、動作は実装定義です:nullポインターが返されるか、または動作はサイズがゼロ以外の値であるかのようになりますが、返されたポインターはオブジェクトへのアクセスに使用されません。
したがって、malloc(0)
はNULL
または有効なポインター逆参照されない場合がありますを返します。どちらの場合でも、free()
を呼び出すことは完全に有効です。
malloc(0)
がたとえばループで呼び出され、n
がゼロの場合を除いて、malloc(n)
の使用はあまりないと思います。
リンクのコードを見ると、著者には2つの誤解があったと思います。
malloc(0)
は有効なポインターを返しますalwaysfree(0)
は悪いです。そのため、彼はartist
および他の変数に常に「有効な」値があることを確認しました。コメントには次のように書かれています:// these must always point at malloc'd data
。
malloc(0)の動作は実装固有です。ライブラリは、メモリを割り当てずに、NULLを返すか、通常のmalloc動作を行うことができます。それが何であれ、それはどこかに文書化されなければなりません。
通常、有効で一意のポインターを返しますが、逆参照しないでください。また、実際には何も割り当てなかったにもかかわらず、メモリを消費する可能性があることに注意してください。
Null以外のmalloc(0)ポインターを再割り当てすることは可能です。
ただし、malloc(0)をそのまま使用することはあまり役に立ちません。これは主に、動的割り当てがゼロバイトであり、それを検証する必要がない場合に使用されます。
このページの別の場所に「malloc(0)は有効なメモリアドレスを返し、その範囲はメモリを割り当てられているポインタのタイプに依存します」という回答があります。この声明は間違っています(その答えに直接コメントするほどの評判がないので、このコメントをその下に直接置くことはできません)。
Malloc(0)を実行するとnotが正しいサイズのメモリを自動的に割り当てます。 malloc関数は、結果のキャスト先を認識しません。 malloc関数は、引数として指定したサイズ番号のみに依存します。 0ではなくintを保持するのに十分なストレージを取得するには、malloc(sizeof(int))を実行する必要があります。
malloc(0)
は、コードが実装に固有の動作に依存していない限り、意味がありません。コードが移植可能であることを意図している場合、malloc(0)
からのNULL戻りが失敗ではないという事実を考慮する必要があります。とにかくartist
にNULLを単に割り当てないのはなぜですか、それは有効な成功結果であり、コードが少なく、メンテナンスプログラマがそれを理解するのに時間をかけないからです。
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
またはmalloc(some_variable_which_might_be_zero)
を使用することもできますが、値が0の場合にNULL戻り値を失敗として扱わないように特別な注意を払う必要がありますが、サイズ0が想定されます大丈夫。
この辺りには半分の正解がたくさんあるので、ここに難しい事実があります。 malloc()
のマンページには次のように書かれています:
サイズが0の場合、malloc()はNULL、またはfree()に後で正常に渡すことができる一意のポインター値のいずれかを返します。
つまり、malloc(0)
の結果が一意であるかNULLでないという保証はまったくありません。唯一の保証は、free()
の定義によって提供されます。ここでも、マンページの内容は次のとおりです。
PtrがNULLの場合、操作は実行されません。
したがって、malloc(0)
が返すものは何でも、free()
に安全に渡すことができます。しかし、NULL
ポインターも同様です。
その結果、書き込みartist = malloc(0);
書き込みよりも優れているartist = NULL;
確かに、私はこれをこれまで見たことがありません。これは、この構文を見たのは初めてです。つまり、機能過剰の古典的なケースです。リードの答えに関連して、オーバーロードされた関数realloc
のように見える類似したものがあることを指摘したいと思います。
realloc(foo, size);
です。 NULL以外のポインターとサイズ0をreallocに渡すと、reallocはfree(…)を呼び出したかのように動作しますrealloc(foo, size);
。 NULLポインターを渡し、サイズがゼロ以外の場合、reallocはmalloc(…)を呼び出したかのように動作しますこれがお役に立てば幸いです、よろしく、トム。
なぜこれをしてはいけないのか...
Mallocの戻り値は実装に依存するため、NULLポインターまたは他のアドレスが返される場合があります。エラー処理コードがサイズと戻り値の両方をチェックしない場合、これによりヒープバッファオーバーフローが発生する可能性があり、安定性の問題(クラッシュ)またはさらに深刻なセキュリティの問題につながります。
サイズがゼロで実装がNULL以外の値を返す場合、返されたアドレスを介してメモリにさらにアクセスするとヒープが破損するこの例を考えてください。
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
このSecure Codingページ を参照してください。CERTCoding Standardsでは、上記の例を取り上げてさらに読みました。
行われた質問に実際に答えるために:それをする理由はありません
Windowsの場合:
void *p = malloc(0);
は、ローカルヒープに長さゼロのバッファを割り当てます。返されるポインターは有効なヒープポインターです。malloc
は最終的にHeapAlloc
を呼び出すデフォルトのCランタイムヒープを使用してRtlAllocateHeap
を呼び出します。free(p);
は、HeapFree
を使用して、ヒープ上の長さ0のバッファーを解放します。解放しないと、メモリリークが発生します。malloc(0)はNULLまたは有効なポインタを返しますが、これらはfreeに正しく渡すことができます。そして、それが指し示すメモリは役に立たないか、読み書きできないように見えますが、常にそうであるとは限りません。 :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
ここではセグメンテーション違反が予想されますが、驚くことに、これは100を出力します!これは、mallocを初めて呼び出すときに、mallocが実際に大量のメモリを要求するためです。その後のmallocの呼び出しはすべて、その大きなチャンクのメモリを使用します。その巨大なチャンクが終わった後にのみ、新しいメモリが要求されます。
Malloc(0)の使用:後続のmalloc呼び出しをより高速にしたい場合は、malloc(0)を呼び出してください(Edgeの場合を除く)。
実際には非常に便利であり、(明らかに私見では)、NULLポインターを返すという許可された動作は壊れています。動的ポインターは、それが指すものだけでなく、アドレスが一意であるという事実にも役立ちます。 NULLを返すと、その2番目のプロパティが削除されます。私がプログラムするすべての組み込みmalloc(実際には非常に頻繁に)には、この動作があります。