malloc(0)の意味は何ですか?


回答:


121

仕様によると、malloc(0)は「nullポインターまたはfree()に正常に渡すことができる一意のポインター」を返します。

これは基本的に何も割り当てませんが、心配することなくfree()の呼び出しに「artist」変数を渡します。実用上は、次のようにするのとほとんど同じです。

artist = NULL;

51
個人的には、NULLに設定する方がクロスプラットフォーム戦略として優れていると思います。free()が(仕様により)入力としてNULLで正常に機能することが保証されているためです。
リードコプシー、2010年

2
C.ロスが述べたように、一部のプラットフォームでは、技術的にはここでポインター(「解放して渡すことができる一意のポインター」)を返すことができますが、これをchar *として扱うと、無効な、終了していない文字。クロスプラットフォームの状況でこれに依存するのは危険な場合があります。
リードコプシー2010年

9
本当によく-.-として「安全のreallocに渡された」と言うでしょうスペックを望む
hanshenrik

1
@NSAddict "sizeofが0を返す空の構造体。例を挙げてください。言語拡張のように聞こえます。
chux-モニカを2016年

1
@hanshenrik誰ができないと言うの?realloc()から返された有効なポインタを渡すことができますmalloc()。十分なはずです。
glglgl

51

C標準(C17 7.22.3 / 1)は言う:

要求されたスペースのサイズがゼロの場合、動作は実装定義です。ヌルポインターが返されるか、返されたポインターがオブジェクトへのアクセスに使用されないことを除いて、サイズがゼロ以外の値であるかのように動作します。

そのため、を参照したり、逆参照できない有効なポインタmalloc(0)返すことができます。どちらの場合でも、それを呼び出すことは完全に有効です。NULLfree()

例えばループで呼び出されたmalloc(0)場合を除いて、私は本当にあまり役に立たないと思いますmalloc(n)、そしてnゼロのます。

リンクのコードを見ると、著者には2つの誤解があると思います。

  • malloc(0)有効なポインタを返し、常に、および
  • free(0) 悪い。

したがって、彼はartist、他の変数が常に「有効な」値を持っていることを確認しました。コメントは多くを言います:// these must always point at malloc'd data


10
それは実装に依存するという事実は、それを多かれ少なかれ完全に役に立たなくします-これはC標準のくだらないビットの1つであり、かなりの数の標準委員会(例えばPJ Plauger)はそれについてうめきました。

10
同意する。場合はmalloc(0)、有効なポインタを返され、その後、malloc()戻ってNULL常に手段「失敗」を、そして0より一貫性のある、もはや特別なケースではありません。
Alok Singhal、2010年

1
mallocメモリの取得に失敗する状況は実装によって定義されるため、実装では、サイズ0の割り当てが常に満たされない(ENOMEM)と定義でき、malloc(0)0を返す(とのerrno==ENOMEM)は一貫しています。:-)
R .. GitHub ICE HELPING ICEの停止

6
あなたreallocはポインタを返すことができますmalloc(0)か?できますrealloc((char*)NULL)か?
ブレーデンベスト

3
@Braden Best両方にはい。
chux-モニカを復活させる

11

malloc(0)の動作は実装固有です。ライブラリはNULLを返すか、メモリが割り当てられていない通常のmalloc動作を行うことができます。それが何であれ、それはどこかに文書化されなければなりません。

通常、有効で一意であるが逆参照されるべきでないポインタを返します。また、実際には何も割り当てなかった場合でも、メモリを消費する可能性があることに注意してください。

null以外のmalloc(0)ポインタを再割り当てすることができます。

ただし、malloc(0)を逐語的に使用してもあまり役に立ちません。これは主に、動的割り当てが0バイトで、検証する必要がない場合に使用されます。


9
malloc()「ハウスキーピング情報」をどこかに保持する必要があります(たとえば、この割り当てられたブロックのサイズ、およびその他の補助データ)。したがって、malloc(0)が返されない場合はNULL、メモリを使用してその情報を格納し、free()dでない場合はメモリリークを構成します。
Alok Singhal、2010年

Malloc実装は、要求されたサイズに加えて、返されるポインターごとに特定の量のデータを追加できるレコード保持を実行します。
user7116 2010年

1
消費されたメモリと割り当てられたメモリは同じことを意味しません。この場合、ほとんどの実装は一意のポインタを返します。つまり、そのポインタのためにアドレス空間の一部を犠牲にする必要があります。アロケータによっては、実際には1バイト以上を割り当てることを意味する場合があります。
コインコイン2010年

1
ライブラリは必要なことをすべて実行できます。まあ、他のmalloc()ユーザーが返さない一意のポインタを返すか、を返すことができますNULL
Alok Singhal、2010年

1
@jldupont:少なくともMicrosoft Cランタイムライブラリはの一意のポインタを返しますmalloc(0)。ただし、標準Cライブラリのまったく同じ実装では、NULLをrealloc(ptr, 0)解放ptrして返します。
Medinoc 2018

5

このページの別の場所に「malloc(0)は有効なメモリアドレスを返し、その範囲はメモリが割り当てられているポインタのタイプによって異なる」という回答があります。このステートメントは正しくありません(その回答に直接コメントするのに十分な評判がないため、このコメントをそのすぐ下に置くことはできません)。

malloc(0)を実行して、正しいサイズのメモリが自動的に割り当てられません。malloc関数は、結果のキャスト先を認識していません。malloc関数は、引数として指定したサイズ番号に完全に依存しています。malloc(sizeof(int))を実行して、たとえば0ではなくintを保持するのに十分なストレージを取得する必要があります。


4

malloc(0)コードが実装に固有の動作に依存していない限り、私には意味がありません。コードが移植可能であることを意図している場合、NULLからの戻り値malloc(0)は失敗ではないという事実を考慮する必要があります。それで、artistとにかくNULLを割り当てないでください。それは有効な成功結果であり、コードが少なく、メンテナンスプログラマが時間をかけてそれを理解する必要がないためです。

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)または、malloc(some_variable_which_might_be_zero)おそらくそれらの用途があるかもしれませんが、値が0の場合、NULLの戻りを失敗として扱わないように特別な注意を払う必要がありますが、サイズは0でも問題ありません。


3

この辺りには真実の答えがたくさんあるので、ここに難しい事実があります。のマンページはmalloc()言う:

sizeが0の場合、malloc()はNULL、または後でfree()に正常に渡すことができる一意のポインタ値を返します。

つまり、の結果がmalloc(0)一意であるか、またはNULL ではないという保証はまったくありません。唯一の保証はの定義によって提供されfree()ます。ここでも、マンページに次のように記載されています。

ptrがNULLの場合、操作は実行されません。

したがって、malloc(0)戻り値が何であれ、安全にに渡すことができますfree()。しかし、NULLポインタも同様です。

したがって、書くこと 書くことよりも決して良いことでartist = malloc(0); はありません artist = NULL;


1
実装がnullでも一意でもないポインタを返すことは許可されていません。そうmalloc(0)すれば、たとえば0x1を返すfree()ことができ、0x0の場合と同じように0x1の特別なケースのチェックを行うことができます。
トッドリーマン

3
@Todd Lehman実装は、あなたが提案するようにするかもしれません。C仕様では、結果が「NULL、または一意のポインタ」でなければならないことが指定されていません。代わりに、「nullポインターまたは割り当てられた領域へのポインターのいずれか」。一意の要件はありません。一意ではない特別な値を返すOTOHは、一意の値に依存するコードを混乱させる可能性があります。おそらくSOのコーナーケースの質問
chux-モニカを復活させる

man* nixで使用される実装定義のフォームを文書化することもできます。この場合はそうではありませんが、それでも一般的なCの標準的なソースではありません
Lundin

@Lundin True。しかし、マンページはC標準よりもはるかにアクセスしやすく、GNU / Linuxシステムのマンページは一般に、実装が準拠する標準を非常によく文書化しています。それらが異なる場合、どのパーツがどの標準に準拠しているかについての情報とともに。私は、どちらも正確であり、GNU拡張であるすべてのビットを宣伝したいという気持ちを持っています...
cmaster-モニカを復活させる

3

なぜこれをしてはいけないのか...

mallocの戻り値は実装に依存しているため、NULLポインターまたはその他のアドレスが返される場合があります。エラー処理コードがサイズと戻り値の両方をチェックしない場合、これによりヒープバッファオーバーフローが発生し、安定性の問題(クラッシュ)またはセキュリティの問題がさらに悪化する可能性があります。

この例を考えてみましょう。返されたアドレスを介してメモリにさらにアクセスすると、ヒープiffのサイズが破損し、実装は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 */
}

詳細については、上記の例を取り上げたCERT Coding StandardsのこのSecure Codingページを参照してください。


リンクが移動されました:wiki.sei.cmu.edu/confluence/display/c/...
Cacahueteフリト

2

確かに、私はこれまでこれまで見たことがありません。これは、この構文を見たのは初めてです。リードの回答に関連して、オーバーロードされた関数のように見える同様のものが存在することを指摘したいと思いますrealloc

  • fooはNULLでなく、サイズはゼロです。 realloc(foo, size);。NULL以外のポインタとサイズ0をreallocに渡すと、reallocはfree(…)を呼び出した場合と同様に動作します。
  • fooはNULLで、サイズはゼロ以外で1より大きいrealloc(foo, size);。NULLポインターを渡し、サイズがゼロ以外の場合、reallocは、malloc(…)を呼び出した場合と同様に動作します。

よろしくお願いいたします。トム。


1

実際に出された質問に答えるために:それをする理由はありません


0

malloc(0)は、NULLまたは空に正しく渡すことができる有効なポインタを返します。そして、それが指すメモリは役に立たないか、読み書きできないように見えますが、常にそうであるとは限りません。:)

int *i = malloc(0);
*i = 100;
printf("%d", *i);

ここではセグメンテーション違反が予想されますが、驚いたことに、これは100を出力します これは、mallocを初めて呼び出すときに、mallocが実際に大量のメモリを要求するためです。その後、mallocを呼び出すたびに、その大きなチャンクのメモリが使用されます。その巨大なチャンクが終わって初めて、新しいメモリが要求されます。

malloc(0)の使用:後続のmalloc呼び出しをより高速にしたい場合は、malloc(0)を呼び出すとそれが実行されます(エッジの場合を除く)。


1
*iあなたの場合、への書き込みはクラッシュしないかもしれませんが、それでも未定義の動作です。鼻の悪魔に気をつけろ!
John Dvorak

1
はい。それは本当です。これは実装固有です。MaxOS Xと一部のLinuxディストリビューションで確認しました。他のプラットフォームでは試していません。そうは言っても、私が説明した概念は、Brain KernighanとDennis Ritchieによる「Cプログラミング言語」という本で説明されています。
Sagar Bhosale 2014年

私は知っています:この質問に対する超遅いコメント。しかし、その使用法については言及されていない場合がありますmalloc(0)。NULL以外の値を返すこれらの実装では、特にDEBUGビルドでは、要求よりも多くの割り当てが行われ、内部ヘッダーの直後を指すポインターが表示されます。これは、あなたが取得することができます感じあなたが割り当て一連の前と後にこれを取得する場合、実際のメモリ使用量のために。例:void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;またはそのようなもの。
ジェシーチザム

Brain KernighanとDennis Ritchieの「Cプログラミング言語」を読みましたが、について何も言っていませんmalloc(0)。どの章もあなたが参照しているのか言ってもらえますか?正確な引用を提供することもいいでしょう。
АндрейБеньковский

0

Windowsの場合:

  • void *p = malloc(0);ローカルヒープに長さ0のバッファを割り当てます。返されるポインタは有効なヒープポインタです。
  • malloc最終的にはHeapAlloc、デフォルトのCランタイムヒープを使用して呼び出しますRtlAllocateHeap
  • free(p);HeapFreeヒープ上の長さ0のバッファを解放するために使用します。解放しないと、メモリリークが発生します。

0

これは実際には非常に便利であり(明らかにIMHO)、NULLポインターを返すという許可された動作は壊れています。動的ポインターは、それが指しているものだけでなく、そのアドレスが一意であるという事実にも役立ちます。NULLを返すと、その2番目のプロパティが削除されます。私がプログラムするすべての組み込みmalloc(実際にはかなり頻繁に)には、この動作があります。



-2

これは、valgrindメモリチェックツールで実行した後の分析です。

==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740==     in use at exit: 0 bytes in 0 blocks
==16740==   total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible

そしてこれが私のサンプルコードです:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
   //int i;
   char *p1;

   p1 = (char *)malloc(0);
   printf("p1 = %p\n", p1);

   free(p1);

   return 0;

}

デフォルトでは、1024バイトが割り当てられます。mallocのサイズを大きくすると、割り当てられるバイト数は1025増加します。


-3

Reed Copseyの回答とmallocのmanページによると、私はテストするためにいくつかの例を書きました。そして、malloc(0)は常に一意の値を与えることがわかりました。私の例を見てください:

char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
    puts("Got a null pointer");
else
    puts("Got a valid pointer");

出力は「Got a valid pointer」ですptr。これはnullではないことを意味します。


-6

malloc(0)有効なメモリアドレスを返します。その範囲は、メモリに割り当てられているポインタのタイプによって異なります。また、メモリ領域に値を割り当てることもできますが、これは使用されているポインタのタイプの範囲内である必要があります。割り当てられたメモリを解放することもできます。例を挙げて説明します。

int *p=NULL;
p=(int *)malloc(0);
free(p);

上記のコードはgcc、Linuxマシンのコンパイラーで正常に動作します。32ビットコンパイラを使用している場合は、整数の範囲、つまり-2147483648〜2147483647の値を指定できます。文字にも同じことが当てはまります。宣言されたポインタのタイプが変更されると、値の範囲はmallocタイプキャストに関係なく変化することに注意してください。

unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);

p 符号なし整数として宣言されているため、charの値は0〜255になります。


5
クレランはこの答えが間違っていると指摘するのは正解です:malloc()キャストについては何も知りません(実際には完全にCでは余分です)。の戻り値を逆参照すると、malloc(0)未定義の動作が呼び出されます。
cmaster-モニカを14年

-6

ここで誤った印象を修正するだけです。

artist = (char *) malloc(0);二度と戻ることはありませんNULL。とは異なりますartist = NULL;。簡単なプログラムを書いて、と比較artistしてくださいNULLif (artist == NULL)は偽でif (artist)あり、真です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.