ptrがNULLであるfree(ptr)はメモリを破壊しますか?


112

理論的には

free(ptr);
free(ptr); 

すでに解放されているメモリを解放しているため、メモリ破損です。

しかし、もし

free(ptr);
ptr=NULL;
free(ptr); 

OSは未定義の方法で動作するので、何が起こっているのかについてこれに関する実際の理論的分析を得ることができません。私が何をしていても、このメモリ破損はありますか?

NULLポインタの解放は有効ですか?


1
Cフリーの標準については不明ですが、C ++ではdelete(NULL)が完全に有効であるため、free(NULL)も有効である必要があります。
Priyank Bolia 2009

14
@Pryank:delete NULLC ++では無効です。deleteは具象型のnullポインター値に適用できますが、には適用できませんNULLdelete (int*) NULLは合法ですが、ではありませんdelete NULL
AnT 2009

つまり、ポインタがNULL freeを指している場合、何も実行されないことになります。つまり、!!! コーディングで毎回、メモリを解放したい場合は、free(ptr)をptr = NULL?
ビジェイ

3
いいえ。ptrメモリをポイントしfree、それを呼び出さない場合、メモリがリークします。それをNULLメモリのハンドルを失うだけに設定すると、リークします。場合ptr であることを起こるNULL、呼び出しはfree無操作です。
GManNickG 09

1
@benjamin:えっ?何が、置き換えることができるという結論にあなたを作ったfree(ptr)ptr = NULL。誰もそのようなことは何も言わなかった。
AnT 2009

回答:


224

7.20.3.2 free関数

あらすじ

#include <stdlib.h> 
void free(void *ptr); 

説明

このfree関数は、が指すスペースのptr割り当てを解除します。つまり、追加の割り当てに使用できるようになります。場合はptrNULLポインタがある、何の動作は発生しません。

ISO-IEC 9899を参照してください。

そうは言っても、実際にさまざまなコードベースを見ると、人々が時々そうしていることに気付くでしょう:

if (ptr)
  free(ptr);

これは、NULLポインターを解放すると、一部のCランタイム(PalmOSの場合は確かに覚えていました)がクラッシュするためです。

しかし、今日でfree(NULL)は、標準で指示されているようにnopであると仮定しても安全だと思います。


29
いいえ、ptr = NULLはfree(ptr)の代わりにはなりません。どちらも完全に異なります
Prasoon Saurav

7
いいえ、それはnullが副作用がないことを意味free(ptr)ptrます。しかし、いずれの場合でも、使用して割り当てられたすべてのメモリ、malloc()またはcalloc()後で使用して解放する必要がありますfree()
Gregory Pakosz 2009

4
ptr = NULLは、誤ってfree(ptr)を呼び出した場合でも、プログラムがsegfaultしないことを保証します。
Prasoon Saurav、2009

2
C標準ではそれはノーオペレーションであると述べていますが、すべてのCライブラリがそのように処理することを意味するわけではないことに注意してください。free(NULL)のクラッシュを確認したので、そもそもfreeを呼び出さないようにするのが最善です。
Derick

6
@WereWolfBoy コールfree(NULL)するNULL前にポインタをテストすることで回避することを意味しますfree()
Gregory Pakosz 2013

22

Cライブラリのすべての標準準拠バージョンは、free(NULL)を何もしないものとして扱います。

とは言え、かつてはfree(NULL)でクラッシュするfreeのバージョンがいくつかありました。そのため、いくつかの防御的なプログラミング手法が推奨されています。

if (ptr != NULL)
    free(ptr);

8
-1 [引用が必要]。古風な伝聞の実装の理論のためにコードスタイルを変更することは悪い考えです。
トーマス、

41
@Tomas-スタイルを変更することはお勧めしませんでした。いくつかのスタイルでこの推奨が引き続き表示される理由を簡単に説明しました。
R Samuel Klatchko、2009


7
@Tomas:問題はバージョン7 Unixのようなものでした。私が学習していたとき、xyz == NULLであるfree(xyz)は、私が学習したマシン(PNXを実行するICL Perqで、System IIIのエクストラを備えたバージョン7 Unixに基づいていました)での緊急災害のレシピでした。しかし、私は長い間そのようにコーディングしていません。
ジョナサンレフラー

2
Netwareも解放されたNULLでクラッシュします...(クラッシュをデバッグしただけです...)
Calmarius 2013年


12

free(NULL)クラッシュしたPalmOSで作業したことを覚えています。


4
興味深い-クラッシュする2番目のプラットフォーム(3BSD以降)になります。
ダグラスリーダー2010年

2
私の記憶が正しければ、PalmにはC標準ライブラリが存在しませんでした。代わりに、Palm OS SDKへの標準ライブラリ呼び出しをマップする、ほとんどサポートされていないヘッダーファイルがありました。多くのことが予想外に作用した。クラッシュNULLは、標準ライブラリと比較したPalmツールボックスの実行上の大きな違いの1つでした。
Steven Fisher、

8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

NULLポインタは安全に削除できます。その場合、操作は実行されません。つまり、free()はNULLポインターに対しては何もしません。


8

推奨される使用法:

free(ptr);
ptr = NULL;

見る:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

NULL後にポインタを設定すると、再度free()呼び出すことができfree()、操作は実行されません。


3
これは、デバッガーでsegfaultを見つけるのにも役立ちます。p = 0のp-> do()でのsegfaultが、解放されたポインタを使用している誰かであることは明らかです。デバッガーにp = 0xbfade12が表示された場合、それほど明白ではありません:)
ニューロ

6

free(NULL)Cで完全に合法であるだけでなく、delete (void *)0およびdelete[] (void *)0C ++で有効です。

ところで、メモリを2回解放すると、通常、なんらかのランタイムエラーが発生するため、何も破損しません。


2
delete 0C ++では正しくありません。delete明示的にポインタ型の式が必要です。delete型指定されたnullポインター値に適用することはできますが、適用することは0できませんNULL
AnT 2009

1
void*どちらも削除できません:Pどのデストラクタを実行する必要がありますか?
GManNickG

1
@GMan:nullポインターであれば削除できvoid *ます。
AnT 2009

わかりました。特にnullのみを扱っていることを忘れていました。
GManNickG 2009

通常は何も破損しませんが、保証はありません。ASLRがこれを実現する可能性はかなり低くなりますが、それでも不可能ではありませんbuf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); 。-運が悪い場合、buf2がbuf1とまったく同じアドレスを取得し、誤ってbuf1を2回解放したため、buf1の2番目の解放時に、buf2を実際に静かに解放しました。 (即時)エラー/クラッシュ/何でも。(ただし、次にbuf2を使用しようとすると、おそらくクラッシュするでしょう-そして、ASLRで実行している場合、このシナリオはほとんど起こりません)
hanshenrik

3

free(ptr)はCで保存されますptrNULL、ほとんどの人が知らないのは、NULL0である必要はないということです。私は古き良き時代の良い例があります。C64のアドレス0には、IOポートがあります。このポートにアクセスするプログラムをCで作成した場合、値が0のポインターが必要になります。対応するCライブラリは0とNULLそれ以降を区別する必要があります。

敬具。


興味深い事実、驚いたことに私を捕まえた。NULLポインターの質問/回答を巡る旅を強要されました。
節足動物


-3

ptrがメモリロケーションをポイントしています。0x100としましょう。

free(ptr)を実行すると、基本的にはメモリマネージャーが0x100を使用して他のアクティビティやプロセスに使用できるようになり、簡単に言うとリソースの割り当て解除になります。

ptr = NULLを実行すると、ptrが新しい場所を指すようになります(NULLが何であるかを気にする必要はありません)。これを行うと、0x100メモリデータのトラックが失われます。これがメモリリークです。

したがって、有効なptrでptr = NULLを使用することはお勧めできません。

代わりに、次を使用して安全なチェックを行うことができます:

if(ptr!= NULL){free(ptr);}

ptrがすでにNULLを指している場所でfree(ptr)を実行すると、何も実行されないため、安全に実行できます。

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