コンパイラがCコードを実行可能なマシンコードに変換すると、タイプ情報を含む多くの情報が破棄されます。あなたが書く場合は:
int x = 42;
生成されたコードは、単にコピーし、メモリの特定のチャンク(通常は4バイトであるかもしれないチャンク)に、特定のビットパターン。メモリのチャンクがタイプint
のオブジェクトであることを機械コードを調べることによって知ることはできません。
同様に、書き込み時:
if (mynode->next_node == NULL) { /* ... */ }
を生成されたコードは、メモリの別のポインタサイズのチャンクを逆参照することにより、メモリのポインタサイズのチャンクをフェッチし、ヌルポインタのシステムの表現に結果を比較します(典型的には全ビット・ゼロ)。生成されたコードは、next_node
が構造体のメンバーであるという事実、または構造体がどのように割り当てられたか、またはそれがまだ存在するかどうかについては何も直接反映していません。
コンパイラはコンパイル時に多くのことをチェックできますが、実行時にチェックを実行するコードを生成するとは限りません。最初にエラーを起こさないようにすることは、プログラマとしての責任です。
この特定のケースでは、free
を呼び出した後、mynode
は不定値を持ちます。どのような有効なオブジェクトも指していませんが、実装がその知識で何かを行う必要はありません。 free
を呼び出すと、割り当てられたメモリが破棄されることはなく、ただちにmalloc
を呼び出すことで割り当て可能になります。
実装方法はのようにチェックを行い、free
の後にポインタを間接参照すると実行時エラーが発生することがあります。しかし、そのようなチェックはC言語では必要ではなく、(a)コストが高くなり、プログラムの実行が遅くなり、(b)チェックですべてのエラーを捕まえることができないため、一般的に実装されません。
Cが定義されているため、プログラムがすべて正常に動作してもメモリ割り当てとポインタ操作が正しく機能します。コンパイル時に特定のエラーを検出すると、コンパイラはそのエラーを診断できます。たとえば、ポインタ値を整数オブジェクトに代入するには、少なくともコンパイル時の警告が必要です。しかし、free
ポインタを逆参照するなどの他のエラーは、プログラムにの定義されていない動作を引き起こします。プログラマとして、最初にこれらのエラーを避けることは、あなた次第です。あなたが失敗した場合、あなたは自分でいる。
もちろん、役立つツールがあります。 Valgrindは1つです。賢明な最適化コンパイラは別のものです。 (最適化を有効にすると、コンパイラはコードの分析をさらに進め、多くの場合、エラーを診断することができます。)しかし、最終的にC言語はあなたの手を保持する言語ではありません。これは鋭いツールです。また、より多くの実行時検査を行うインタープリター言語など、より安全なツールを構築するために使用できるツールです。
無料通話でメモリが蒸発すると思いますか?それはまだそこにある(ない)か、それは別の意味を持つ可能性があります。 – wildplasser
@wildplasserあなたはそこでsnarkyされていますか?私は言語の構文だけでなく、それがなぜ機能するのかを理解しようとしています。もちろん、メモリは蒸発しません。しかし、私が* pointer-> memberを書くと、その仕組みがどのように機能しているのか、そしてポインタがfree()の後でまだ動作している理由が分かりません。希望は意味をなさない。 – Ducain
ポインタの値は同じです。 free()を呼び出した後、あなたはメモリを放棄しました:あなたはmalloc/freeに、もう使用したくないと言ったのです。それを電話番号と比較してください:私の電話の添付ファイルを終了した後、私の番号はもはや有効ではありません。しかし、まだダイヤルしようとすることができます。それは私が電話に答えるかもしれない。または騒音。または全く異なる誰か。番号(=アドレス)はまだ存在しますが、それを使用することはもはや有効ではありません。それは原子力発電所のコントロールを指すことができる... – wildplasser