6

私のテスト中に、free()の後にポインタを使用できることがわかりました。私は次のコードを持っています:

typedef struct{

    int module_id;
    int adc_id;
    struct config_line * pnext;

} config_line;
config_line * create_list()
{

config_line * phead = (config_line *) malloc(sizeof(config_line));
phead->pnext=NULL;
phead->module_id = 1;
phead->adc_id = 2;

printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);

free(phead);

printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);

phead->module_id = 2;
phead->adc_id = 5;

printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
}

このコードの出力は次のとおりです。

module_id=1 adc_id=2
module_id=0 adc_id=2
module_id=2 adc_id=5

free(phead)の後、ポインタへのアクセス(読み取りと書き込み)を取得できるのはなぜですか?セグメンテーション違反がないのはなぜですか?

4

5 に答える 5

23

無効なポインタを使用すると、未定義の動作が発生するためです。そして、それは振る舞いが...まあ...未定義であることを意味します。クラッシュする義務はありません。

于 2013-03-15T12:12:49.160 に答える
14

を呼び出すと、を指すfree(phead)メモリは解放されますが、の値は変更されず、ダングリングポインタになります。すでに解放されているメモリにアクセスすると、未定義の動作が発生します。pheadpheadphead

NULLポインタが指すメモリを解放したら、ポインタに割り当てることをお勧めします。

free(phead);
phead = NULL;
于 2013-03-15T12:14:39.860 に答える
8

メモリはまだプロセスにマップされていますが、割り当てられていないためです。Cプログラムで実行されるメモリ管理には2つのレベルがあります。1つは、カーネルが書き込み可能なページを提供することです。プロセスがマップしたより多くのメモリを必要とする場合、カーネル(sbrk)からより多くを要求する必要があります。ただし、これは大きなチャンクになるため、mallocはそれをチャンクにスライスし、必要に応じてさらにページを要求しますが、可能な場合は、プログラムにすでに割り当てられているメモリを使用します。freeは、それを使用していたすべての割り当てが解放されるまで、ページを返すことはできません。

したがって、カーネルが提供するメモリアクセス違反(SIGSEGV)はかなり粗く、ほとんどのメモリエラーを検出できず、カーネルの観点から致命的なものだけを検出できます。あなたは自由にmallocの追跡データをゴミ箱に捨てたり、ほとんどの割り当ての終わりを過ぎて、そして多くの解放の後に読んだりすることができます。

ただし、メモリエラーをコミットしないでください。非常に厳密なVMを使用するvalgrindを使用してアプリを実行し、すべてのエラーをチェックしてすぐに潰します。

于 2013-03-15T12:16:19.753 に答える
5

頭が切り落とされているにもかかわらず、なぜ鶏は走り回って飛び回るのですか?これは常に発生するとは限らないことに注意してください。一部の鶏はすぐに動きを止めるかもしれませんが、他の鶏は何ヶ月も走り続けるかもしれません。それが起こるとき、それは起こるので起こります。それは私たちがペットの頭を切り落とす必要があるという意味ですか?

ペットの頭を切り落とすように、解放されたメモリを使用することは悪い考えです。それはそれが否定的な結果を生み出すという意味ではありません。プログラムはマシン上で期待どおりに実行され続ける可能性がありますが、if (fubar)fubarが無効なポインタである場合)他の実装でプログラムが誤動作するのに十分な場合があります。

実装が動作を定義する(または定義しない)ためのこのアイデアの自由は、正式には未定義動作として知られています。C実装がどのように動作するかを指示する一連のドキュメントであるC標準が動作を定義していないため、動作は未定義です。したがって、ペットの頭を切り落とすように、未定義の行動はすべて避ける必要があります。

于 2013-03-15T12:31:46.293 に答える
4

メモリ(ポインタ)を解放すると、そのメモリが空きメモリプールに戻されるためです。メモリは単に消えるだけでなく、そのメモリが再度割り当てられて書き込まれるまで、その内容は消去されません。

したがって、メモリが解放された後、メモリにアクセスすることは非常に可能です。いつでも割り当てたり変更したりできるので、想像できるように良いアイデアではありません。

于 2013-03-15T13:10:18.527 に答える