web-dev-qa-db-ja.com

free()はヒープのメモリアドレスにどのように影響しますか?

この割り当てでは、malloc()(_var1_および_var2_という名前)を使用して2つのint型変数を割り当て、各変数のアドレス(スタック上のポインターのアドレスとヒープ上のアドレス)、次にfree()を使用して_var1_の割り当てを解除し、アドレスを再度出力してから、ヒープ内に_var1_に別のスペースを割り当て、アドレスを3回印刷します。インストラクターは、_var1_のヒープアドレスが変更されることになっていることを示しようとしていると思いますが、コードからfree(var1)を削除しない限り、常に同じままです。インストラクターは同様のデモンストレーションを行いましたが、変数の割り当てを解除するためにfree()を使用しなかったため、これがどのように機能するかはわかりませんでした。

これが私のコードです:

_#include <stdio.h>
#include <stdlib.h>

void main()
{

int *var1 = (int*)malloc(sizeof(int)); 
*var1 = 1000;                   
int *var2 = (int*)malloc(sizeof(int)); 
*var2 = 2000;

printf("Addresses of var1\n");
printf("Pointer on stack: %p / Heap: %p\n\n", &var1, var1); 
printf("Addresses of var2\n");
printf("Pointer on stack: %p / Heap: %p\n\n", &var2, var2);

free(var1);

printf("AFTER DEALLOCATING var1 FROM THE HEAP\n");
printf("Addresses of var1\n");
printf("Pointer on stack: %p / Heap: %p\n\n", &var1, var1); 
printf("Addresses of var2\n");
printf("Pointer on stack: %p / Heap: %p\n\n", &var2, var2);

var1 = (int*) malloc(sizeof(int));
*var1 = 1500;

printf("NEW MEMORY ADDRESS ALLOCATED FOR var1\n");
printf("Addresses of var1\n");
printf("Pointer on stack: %p / Heap: %p\n\n", &var1, var1); 
printf("Addresses of var2\n");
printf("Pointer on stack: %p / Heap: %p\n\n", &var2, var2); 

}
_

このコードにより、次の出力が得られます。

_Addresses of var1
Pointer on stack: 0xffffcbf8 / Heap: 0x600000390

Addresses of var2
Pointer on stack: 0xffffcbf0 / Heap: 0x6000003b0

AFTER DEALLOCATING var1 FROM THE HEAP
Addresses of var1
Pointer on stack: 0xffffcbf8 / Heap: 0x600000390

Addresses of var2
Pointer on stack: 0xffffcbf0 / Heap: 0x6000003b0

NEW MEMORY ADDRESS ALLOCATED FOR var1
Addresses of var1
Pointer on stack: 0xffffcbf8 / Heap: 0x600000390

Addresses of var2
Pointer on stack: 0xffffcbf0 / Heap: 0x6000003b0
_

ご覧のとおり、ヒープアドレスは、割り当てを解除しても_var1_の場合は変更されず、_var1_にメモリスペースを再度割り当てても変更されません。ただし、プログラムからfree(var1)行を削除すると、_var1_に2番目のメモリスペースが割り当てられ、ヒープ上のメモリスペースがポイントされます。メモリアドレスは異なります。

_Addresses of var1 
Pointer on stack: 0xffffcbf8 / Heap: 0x600000390

Addresses of var2
Pointer on stack: 0xffffcbf0 / Heap: 0x6000003b0

AFTER DEALLOCATING var1 FROM THE HEAP
Addresses of var1
Pointer on stack: 0xffffcbf8 / Heap: 0x600000390

Addresses of var2
Pointer on stack: 0xffffcbf0 / Heap: 0x6000003b0

NEW MEMORY ADDRESS ALLOCATED FOR var1
Addresses of var1
Pointer on stack: 0xffffcbf8 / Heap: 0x600000420

Addresses of var2
Pointer on stack: 0xffffcbf0 / Heap: 0x6000003b0
_

(明確にするために、前のコードからfree(var1)を削除するだけだったので、「AFTER DEALLOCATING var1」セクションには、前のセットとまったく同じヒープアドレスが表示されますが、ヒープアドレスは変更されます3番目のセクションのvar1の。)

ここで何が起こっているのか誰か教えてもらえますか?私が思いつくことができる唯一の論理的な説明は、free()を使用して_var1_の割り当てを解除してからアドレスを出力すると、それが指している最後のアドレスを出力するだけであり、 2回目は_var1_にメモリを割り当てていますが、これは単に前のアドレスを新しい値_var1_で「埋め戻し」ているだけです。これは意味がありますか?コードにエラーがありますか、それとも変数のメモリの割り当てを解除してから再割り当てするときにCがどのように動作するのですか?

14
Dustin R.

mallocが、メモリが解放されてから再割り当てされたときに同じアドレスを返すことは完全に正常です。また、異なるアドレスを返すことも正常です。

malloc呼び出しを変更して、元の割り当てとは異なるサイズを要求すると、mallocが準備した古いブロックでは新しい要求に十分でない可能性があるため、異なるアドレスを取得する可能性があります。しかし、それらで十分かもしれないので、アドレスは変更されないかもしれません。

ちなみに:

  • void main()が正しくありません。 int main(void)である必要があります。
  • 指しているスペースが解放された後にアドレスを印刷することは、C標準ではサポートされていません。それが「機能する」ことは珍しいことではありませんが、それは適切ではありません。 C 2018 6.2.4 2は、「ポインターが指す(またはちょうど過ぎた)オブジェクトがその存続期間の終わりに達すると、ポインターの値は不確定になります」と述べています。 mallocで割り当てられたオブジェクトがfreeで解放されると、その存続期間は終了します。
11

私が思いつくことができる唯一の論理的な説明は、free()を使用してvar1の割り当てを解除してからアドレスを出力する場合、それが指している最後のアドレスを出力するだけであるということです。

一種の権利。ポインタを解放しても、ポインタの内容にはまったく影響しません。もっと正確に言うと、解放された後の値は不確定です。実際、標準によれば、freeを呼び出す前に行ったアドレスを含むポインターを信頼することさえできません。私の知る限り、ほとんどの場合そうなりますが、信頼することはできません。

標準は言う:

C 2018 6.2.4 2:「ポインターが指す(またはちょうど過ぎた)オブジェクトがその存続期間の終わりに達すると、ポインターの値は不確定になります。」

よくある間違いは、ポインタを適切に解放したかどうかをチェックするためにテストif(ptr == NULL)を使用することです。これは機能しません。

4
klutt

最初の例では、ヒープを指すために使用されたポインターがfree()の後のスタックで変更されないままになっている場所の値。ただし、そのアドレスにはアクセスできなくなります。

彼らが変数を再度割り当てるとき、同じアドレスを取得することは不思議ではありません。そのアドレスに適切なサイズの使用可能なセグメントがあるはずだからです。ただし、同じアドレスを取得できるとは限りません。使用可能なアドレスから最適なアドレスは、ライブラリコードによって処理されます。

4
Lundin