执行free()操作符从动态变量中删除地址
Does free() operator delete the address from the dynamic variable?
让我们考虑下面的程序:
int main ()
{
int *p, *r;
p = (int*)malloc(sizeof(int));
cout<<"Addr of p = "<<p <<endl;
cout<<"Value of p = "<<*p <<endl;
free(p);
cout<<"After free(p)"<<endl;
r = (int*)malloc(sizeof(int));
cout<<"Addr of r = "<<r <<endl;
cout<<"Value of r = "<<*r <<endl;
*p = 100;
cout<<"Value of p = "<<*p <<endl;
cout<<"Value of r = "<<*r <<endl;
return 0;
}
:
Addr of p = 0x2f7630
Value of p = 3111728
free(p)
Addr of r = 0x2f7630
Value of r = 3111728
*p = 100
Value of p = 100
Value of r = 100
在上面的代码中,p和r是动态创建的。创建并释放p。r是在p释放后创建的。在改变p中的值时,r的值也会改变。但是我已经释放了p的内存,那么为什么在改变p的值时,r的值也被修改为与p相同的值?我得出了以下结论。如果我是对的,请评论一下。解释:指针变量p和q是动态声明的。初始存储垃圾值。指针变量p被释放/删除声明了另一个指针变量r。r分配的地址与p的地址相同(p仍然指向旧地址)。现在,如果p的值被修改,r的值也被修改为与p的值相同的值(因为两个变量都指向相同的地址)。操作符free()仅从指针变量中释放内存地址,并将该地址返回给操作系统以供重用,但指针变量(在本例中为p)仍然指向相同的旧地址。
free()
函数和delete
运算符不改变指针的内容,因为指针是按值传递的。
但是,使用free()
或delete
后,指针所指向位置的东西可能不可用。
如果我们有内存位置0x1000:
+-----------------+
0x1000 | |
| stuff in memory |
| |
+-----------------+
假设指针变量p
包含0x1000, 或指向内存位置0x1000。
在调用free(p)
之后,允许操作系统重用0x1000处的内存。它可能不会立即使用它,也可能将内存分配给另一个进程、任务或程序。
但是,变量p
没有改变,所以它仍然指向内存区域。在这种情况下,变量p
仍然有一个值,但是不应该解引用(使用内存),因为您不再拥有内存。
你的分析在某些方面表面上很接近,但并不正确。
p
和r
在main()
的第一条语句中被定义为指针。它们不是动态创建的。它们被定义为与main()
一起自动存储持续时间的变量,因此当(在您的程序中,实际上是if) main()
返回时,它们将停止存在。
创建和释放的不是p
。malloc()
动态分配内存,如果成功,返回一个标识动态分配内存的指针(如果动态分配失败,则返回一个NULL
指针),但不初始化内存。malloc()
返回的值(在c++中需要转换为指向int
的指针后)被赋值给p
。
你的代码然后打印p
的值。
(我用斜体突出显示了下一段,因为我将在下面提到它)
下一条语句输出*p
的值。这样做意味着访问p
所指向的地址的值。然而,该内存是未初始化的,因此访问*p
的结果是未定义的行为。在您的实现(编译器和库)中,此时恰好会产生一个"垃圾值",然后将其打印出来。然而,这种行为并不能保证——它实际上可以做任何事情。不同的实现可能会产生不同的结果,例如异常终止(程序崩溃),重新格式化硬盘驱动器,或者(在实践中明显不太可能)通过计算机的扬声器播放Primitives的歌曲"crash"。
在调用free(p)
之后,代码将使用指针r
执行类似的序列。
赋值*p = 100
具有未定义的行为,因为p
保存了第一个malloc()
调用返回的值,但该值已传递给free()
。因此,就您的程序而言,内存不再保证存在。
之后的第一个cout
语句访问*p
。由于p
不再存在(已被传递给free()
),这给出了未定义的行为。
之后的第二个cout
语句访问*r
。该操作具有未定义的行为,原因与我在上面斜体段落中描述的完全相同(对于p
,就像当时一样)。
p
和r
(因为malloc()
在两种情况下都返回相同的值0x2f7630
),在两种情况下打印垃圾值,然后(在语句*p = 100
之后)在打印*p
和*r
时打印100
的值。
然而,这些结果都不能保证。没有保证的原因是,c++标准中"未定义行为"的含义是,该标准对允许的行为没有任何限制,因此实现可以自由地做任何事情。对于特定的实现,在编译、链接和运行代码的特定时间,您的分析可能是正确的。它甚至可能下周是正确的,但从现在起一个月后更新你的标准库(例如应用错误修复)是不正确的。对于其他实现可能不正确。
最后,还有几个小问题。
首先,你的代码是不完整的,甚至不能以你所描述的形式编译。在上面的讨论中,我假设您的代码实际上以
开头。#include <iostream>
#include <cstdlib>
using namespace std;
第二,malloc()
和free()
是标准库中的函数。它们不是运算符。
你对实际情况的分析是正确的;然而,程序不能保证以这种方式可靠地运行。每次在free(p)
之后使用p
都会"引发未定义的行为"。(当您访问*p
和*r
而没有事先写任何内容时,也会发生这种情况。)未定义行为比仅仅产生不可预测的结果更糟糕,比仅仅潜在地导致程序崩溃更糟糕,因为编译器被明确地允许假设引发未定义行为的代码永远不会执行。例如,编译器将您的程序视为与
int main() {}
因为在你的程序中没有不引起未定义行为的控制流路径,所以一定是程序永远不会运行的情况!
free()
释放堆内存供操作系统重用。但是存在于内存地址中的内容不会被擦除/移除
- 将数组的地址分配给变量并删除
- 根据模板类型有条件地删除变量
- 我无法删除 wxApp 类的成员变量
- 使用 ostream 变量删除代码重复
- 如何一次删除"cmake -D"定义的所有变量?
- 如何删除作为C++联合的成员变量的字符串对象
- 从文件名变量中删除".txt"
- 如何删除可以是指针(模板)的变量?
- C :动态分配的变量未在clang中删除
- 从函数中删除动态内存分配,但无法访问变量
- 如果我不删除动态创建的变量会发生什么
- C :从双变量的分数部分中删除尾随零
- 您可以删除本地静态变量吗?
- 将删除运算符放置在何处以进行动态变量
- 在堆上创建的变量未在 C++ 中删除
- 删除父类时,方法局部静态变量会发生什么情况
- 为什么删除成员变量的复制构造函数不会阻止默认的复制构造函数
- 是否可以使用 lambda 初始化变量(删除复制 ctor 时)
- C++ 通过无序变量删除二叉搜索树
- 基于一个1变量删除文本文件中的特定行