3
gcc (GCC) 4.7.0
c89

こんにちは、

ここで正しく考えているのだろうか。mallocを使用してメモリを割り当てる場合。mallocは、メモリ内のサイズへのポインタを返します。

したがって、メモリを割り当てる前に、すべてのポインタの値はNULLになります。

このコードスニペットの使用:

struct address *db_row = NULL;

db_row = malloc(sizeof(struct address));
db_row->name = malloc(sizeof(char) * 10);
db_row->email = malloc(sizeof(char) *10);

free(db_row->name);
free(db_row->email);
free(db_row);

メモリを割り当てる前に、db_rowのgdbデバッガーでこれを実行しました。

(gdb) p db_row
$20 = (struct address *) 0x0
(gdb) p *db_row
Cannot access memory at address 0x0

メモリアドレスが割り当てられていないので、これは正しいです。メモリを割り当てた後、同じことをすると次のようになります。

(gdb) p db_row
$25 = (struct address *) 0x602310
(gdb) p *db_row
$26 = {id = 0, set = 0, name = 0x0, email = 0x0}

ただし、メモリを解放した後も同じメモリアドレスを取得しますが、メモリを割り当てる前の最初のケースのようにNULLにすべきではありませんか?

メモリを解放した後:

(gdb) p db_row
$28 = (struct address *) 0x602310
(gdb) p *db_row
$27 = {id = 6300480, set = 0, name = 0x602330 "", email = 0x602350 " #`"}

まだ同じメモリ位置を指していることがわかりますが、これは正しいですか?

最後に、これを最後に追加して、ダブルフリーを実行できるかどうかを確認しました。

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

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

freeへの2回目の呼び出しでスタックダンプを取得します。しかし、安全対策として、ダブルフリーをしようとしていないことを常に確認する必要がありますか?

ポインタを解放した後、ポインタをNULLに設定する価値はありますか?

db_row = NULL;

提案をありがとう、

4

4 に答える 4

5

しかし、安全対策として、NULLポインターを解放しようとしていないことを常に確認する必要がありますか?

free()ポインタを使った呼び出しNULLは安全で、何も起こりません。呼び出しはポインタではありません。これを明示的に行うことができますfree()。呼び出し後にポインターを実行すると、同じポインター変数でのダブルフリーが防止されます。NULLNULLfree()

/* Assuming 'db_row' is referring to a valid address
   at this stage the following code will not result
   in a double free.*/
free(db_row);
db_row = NULL;
free(db_row);

別のポインタ変数が同じアドレスを指していて、に渡されたfree()場合でも、ダブルフリーが発生します。

ポインタがNULL有効でないからといって、それが有効なアドレスを指していることを保証するものではありません。free()ダブルが発生しないようにするのはプログラマーの責任です。NULLの呼び出し後にポインター変数を指定するとfree()、複数のポインター変数が同じアドレスを指す可能性があるため、保証は提供されません。


しかし、安全対策として、ダブルフリーをしようとしていないことを常に確認する必要がありますか?

ポインタ変数をクエリして、それが保持しているアドレスのメモリがすでにfree()dであるかどうかを判断する方法はありません。ポインタ変数はアドレスを保持しますが、それ以上のものはありません。

于 2012-09-19T10:53:58.217 に答える
3

null変数のスコープの最後にいない限り、ポインタを解放した後にポインタを設定することをお勧めします。はい、それをfree行わないのは正常です。

ポインタがの場合、それnullを呼び出すのfreeは安全であり、ポインタにアクセスするとコアダンプが生成されます。freeこれは、に設定されていない解放されたポインタを使用した場合に発生する可能性のあるメモリの破損や二重化よりもデバッグがはるかに簡単ですnull

于 2012-09-19T10:57:34.893 に答える
2

ここで明確にするために、mallocのmanページから引用します。

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

要約すると、次のようになります。

  1. Freeは、メモリ割り当て関数によって返されたポインタを受け取ります(NULLまたは有効)
  2. NULLの場合、何も起こりません
  3. 有効なポインタの場合、メモリを解放します

ここでは、指しているアドレスの変更については何も述べていません。ptrそれはあなた次第です。したがって、次のことを行うのは非常に安全です。

int *p = malloc(sizeof(int));
*p = 5;
printf("p=%d\n",*p);
free(p);
p = NULL;

free()これで、ポインタpで一日中電話をかけることができ、問題ありません。ダブルコールでエラーが発生することが心配な場合free()は、最近のバージョンのLinux libc(5.4.23以降)およびGNU libc(2.x)には、次のような安全なメカニズムがあります。MALLOC_CHECK_

スタックがクラッシュする代わりに、次のようなメッセージが表示されます。 *** glibc detected *** ./a.out: free(): invalid pointer: 0x0804b008 ***

次のように使用できます。

  1. export MALLOC_CHECK_=0mallocチェックをオフにし、(おそらく)プログラムをクラッシュさせる
  2. export MALLOC_CHECK_=1上記の警告メッセージが表示されます
  3. export MALLOC_CHECK_=2abort(1)を呼び出し、コードのバックトレースを提供します
  4. export MALLOC_CHECK_=3一緒にオプション1|2です
于 2012-09-19T11:59:00.063 に答える
2

メモリを解放した後も同じメモリアドレスを取得しますが、メモリを割り当てる前の最初のケースのようにNULLにすべきではありませんか?

free()割り当てられたメモリのみを解放するためです。ポインタをに設定しませんNULL

しかし、安全対策として、NULLポインターを解放しようとしていないことを常に確認する必要がありますか?

渡されfree()たポインタがnullポインタの場合、アクションは発生しません(C99セクション7.20.3.2)。

それらを解放した後にポインタを設定する価値はありますNULLか?

そうすることにはまったくメリットがありません。多くの場合、問題を隠してしまい、何らかの形で醜い頭を上げることになります。

ダングリングポインタやダブルフリーの問題を回避するための防御的で疑わしいプログラミングスタイルであり、同じfree()ポインタで呼び出されないように自分自身を保護しようとします。実際には、同じポインタに異なるポインタを使用すると、ダブルフリーの問題が発生することがよくあります。メモリとこれらの異なるポインタがに渡されます。 free()

ポインタを作成する方法はNULL、2番目のより一般的なバグシナリオでは何もしません。これらの状況はすべて、いくつかの良い考えと定期的なコードレビューを入れてプログラムを作成することによってのみ回避できます。

于 2012-09-19T10:52:38.987 に答える