我想知道当一个系统如何释放内存时,malloc()调用是否与你分配malloc()的初始变量绑定在一起。
例如,我可以执行以下操作:
void * ptr1 = malloc(50);
void * ptr2 = ptr1;
ptr1 = malloc(25);
free(ptr2);
我打算释放最初分配给ptr1的内存,但后来用另一个指针释放它。
让我们一步一步地介绍(UNDEF
意味着我们不知道什么是值; valid
意味着指针可以安全使用):
void *ptr1, *ptr2; /* ptr1=UNDEF (invalid), ptr2=UNDEF (invalid) */
ptr1 = malloc(50); /* ptr1=0xAAA (valid), ptr2=UNDEF (invalid) */
ptr2 = ptr1; /* ptr1=0xAAA (valid), ptr2=0xAAA (valid) */
ptr1 = malloc(25); /* ptr1=0xBBB (valid), ptr2=0xAAA (valid) */
free(ptr2); /* ptr1=0xBBB (valid), ptr2=UNDEF (invalid) */
free()
不知道它传递的指针存储在哪个变量中;不保证(但也不保证不)以任何方式更新变量或与变量交互。从应用程序开发人员的角度来看,有效改变的是,实际使用该指针是否安全,或者在返回它的malloc()
调用期间分配给内存块的任何其他引用是否安全。
正如@M.M in comments所提到的,C语言规范是明确的,指向未释放对象的指针的值是未定义的,并允许编译器以任何方式修改它;请参阅Why does MISRA C state that a copy of pointers can cause a memory exception?进一步讨论。
简短回答:是的
更长的回答:
你不是在“变量”上调用自由,而是在存储在变量中的值上调用。
为了更好地理解发生了什么,最好将内存视为一个大字节数组,并将指针可视化为该数组的数字索引。在您可能遇到的大多数架构上,这实际上是幕后发生的事情。
当你这样做
void * ptr1 = malloc(50);
malloc
保留一个50字节的块并返回指向该块的指针。该指针只不过是一个数字索引,告诉我们内存中保留块的起始位置。
从理论上讲,我们可以(在某些架构上)编写
int ptr1 = (int)malloc(50);
我们没有这样做的原因是:
sizeof(int)
可能不够大,无法容纳指针void *
告诉编译器存储在ptr1
中的数值应该被视为内存地址。如果我们继续查看您的代码:
void * ptr2 = ptr1;
这里没有什么神奇的事情发生。存储在ptr1
中的“数值”被复制到ptr2
中,就像ptr1
和ptr2
是正常的整数变量一样。
ptr1 = malloc(25);
在这里,您使用新的“数值”覆盖ptr1
的内容,但旧值仍然作为ptr2
中的副本存在。
free(ptr2);
在这里,您可以使用存储在free
中的值调用ptr2
。这是malloc(50)
返回的值。 free
不关心哪个变量持有该值/地址。它只关心值/地址指向使用malloc
保留的内存块的第一个字节。
理论上,如果你知道malloc(50)
返回值0xb00b1e5就可以了
free((void *) 0xb00b1e5);
但是你无法安全地预测malloc
会返回什么,所以不要这样做。