動的メモリ割り当てに関しては、私は初心者です。メモリを使用しvoid free(void *ptr)
てメモリを解放すると、割り当てが解除されますが、ポインタの内容は削除されません。何故ですか?最近のCコンパイラに違いはありますか?
5 に答える
コンピュータはメモリ自体を「削除」するのではなく、そのメモリセルへのすべての参照の使用を停止し、価値のあるものがそこに格納されていることを忘れます。例えば:
int* func (void)
{
int x = 5;
return &x;
}
printf("%d", *func()); // undefined behavior
関数が終了すると、プログラムx
は格納されているメモリ位置の予約を停止し、プログラムの他の部分(またはおそらく別のプログラム)はそれを自由に使用できます。したがって、上記のコードは5を出力したり、ガベージを出力したり、プログラムをクラッシュさせたりする可能性があります。有効でなくなったメモリセルの内容を参照することは未定義の動作です。
動的メモリも例外ではなく、同じように機能します。を呼び出すとfree()
、メモリのその部分の内容を誰でも使用できるようになります。
また、この質問を参照してください。
問題は、解放された後にメモリにアクセスすることは未定義の動作であるということです。メモリの内容が未定義であるだけでなく、それらにアクセスすると何かが発生する可能性があります。コードのデバッグバージョンをビルドするときに少なくとも一部のコンパイラは、デバッグを支援するために実際にメモリの内容を変更しますが、リリースバージョンでは通常それを行う必要がないため、メモリはそのままになりますが、とにかく、それはあなたが安全に頼ることができるものではありません、解放されたメモリにアクセスしないでください、それは安全ではありません!
Cでは、パラメーターは値によって渡されます。したがってfree
、の値を変更することはできませんptr
。
変更を加えると、free
関数内の値のみが変更され、呼び出し元の変数には影響しません。
また、それを変更することはあまり役に立ちません。同じメモリを指す複数のポインタが存在する可能性があり、それらはすべて解放時にリセットする必要があります。言語はそれらすべてを追跡することはできないため、プログラマーはポインターを処理する必要があります。
解放後にメモリ位置をクリアすることはオーバーヘッドであり、通常は必要ないため、これはごく普通のことです。セキュリティ上の懸念がある場合は、解放する前に領域をクリアする関数内で解放呼び出しをラップできます。また、これには割り当てサイズの知識が必要であり、これは別のオーバーヘッドであることに気付くでしょう。
実際、Cプログラミング言語では、オブジェクトの存続期間が経過すると、オブジェクトを指すポインターの値でさえ不確定になる、つまり、元の値を保持するためにポインターに依存することさえできないと指定されています。
これは、優れたコンパイラがすべての変数をメモリではなくCPUレジスタに積極的に格納しようとするためです。free
したがって、プログラムフローが引数で指定された関数を呼び出すことを確認した後、たとえば、再び割り当てられるまで、他の使用のためptr
に空きのレジスタをマークできます。ptr
ptr = malloc(42);
これら2つの間で、値を変更したり、元の値と等しくないことを比較したり、または他の同様の動作を確認したりすることができます。これが起こるかもしれないことの例です。