让我们考虑下面的程序:
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 已创建并已释放。在 p 被释放后创建 r 。 在更改 p 中的值时, r 的值也会更改。但是我已经释放了 p 的内存,那么为什么在更改 p 的值时, r 的值也会被修改为相同的价值如 p ?
我得出了以下结论。如果我是对的,请评论?
说明: 动态声明指针变量 p 和 q 。最初存储垃圾值。指针变量 p 已释放/已删除。声明了另一个指针变量 r 。分配给 r 的地址与 p 的地址相同( p仍然指向旧地址)。现在,如果 p 的值被修改, r 的值也会被修改为与 p 相同的值(因为两个变量都是指向同一地址)。 运算符 free()仅从指针变量释放内存地址并将地址返回给操作系统以供重用,但指针变量( p 在这种情况下) )仍然指向同一个旧地址。
答案 0 :(得分:3)
free()
函数和delete
运算符不会更改指针的内容,因为指针是按值传递的。
但是,使用free()
或delete
后,指针指向的位置中的内容可能无法使用。
所以如果我们有内存位置0x1000:
+-----------------+
0x1000 | |
| stuff in memory |
| |
+-----------------+
让我们假设指针变量p
包含0x1000,或指向内存位置0x1000 。
调用free(p)
后,允许操作系统重用0x1000的内存。它可能不会立即使用它,也可能将内存分配给另一个进程,任务或程序。
但是,变量p
未被更改,因此它仍然指向内存区域。在这种情况下,变量p
仍然有一个值,但是不应该取消引用(使用内存),因为您不再拥有内存。
答案 1 :(得分:3)
您的分析在某些方面表面上很接近但不正确。
p
和r
被定义为main()
的第一个语句中的指针。不是动态创建的。它们被定义为main()
的自动存储持续时间的变量,因此当(实际上如果,在程序的情况下)main()
返回时,它们就不再存在。
创建和释放的不是p
。 malloc()
动态分配内存,如果成功,则返回一个指针,该指针标识动态分配的内存(如果动态分配失败,则为NULL
指针)但不初始化它。 malloc()
返回的值(在转换为指向int
的指针后,在C ++中是必需的)分配给p
。
然后您的代码会打印p
。
(我已经用斜体突出显示了下一个段落,因为我将在下面回复它。)
下一个语句打印*p
的值。这样做意味着访问p
指向的地址处的值。但是,该内存未初始化,因此访问*p
的结果是未定义的行为。通过您的实现(编译器和库),此时恰好会产生&#34;垃圾值&#34;然后打印出来。但是,这种行为并不能保证 - 它实际上可以做任何事情。不同的实现可能会产生不同的结果,例如异常终止(程序崩溃),重新格式化硬盘驱动器,或[在练习中明显不太可能]播放歌曲&#34; Crash&#34;由Primitives通过您的计算机扬声器。
调用free(p)
后,您的代码会使用指针r
进行类似的序列。
作业*p = 100
具有未定义的行为,因为p
包含第一个malloc()
调用返回的值,但已传递给free()
。因此,就您的程序而言,不再保证存在该内存。
之后的第一个cout
语句访问*p
。由于p
不再存在(已传递给free()
),因此会产生未定义的行为。
之后的第二个cout
语句访问*r
。该操作具有未定义的行为,原因与我在上面的斜体段中所描述的完全相同(对于p
,因为它是当时)。
但请注意,代码中出现了五次未定义的行为。即使发生了一个未定义行为的单个实例,所有的赌注都会因为能够预测程序的行为而被取消。通过实现,结果恰好是打印p
和r
具有相同的值(因为malloc()
在两种情况下都返回相同的值0x2f7630
),打印垃圾值在这两种情况下,然后(在声明*p = 100
之后)在打印100
和*p
时打印*r
的值。
但是,这些结果都不能得到保证。不能保证的原因是&#34;未定义的行为的含义&#34;在C ++标准中,标准没有对允许的内容进行任何限制,因此实现可以自由地执行任何操作。对于特定的实现,在编译,链接和运行代码的特定时间,您的分析可能是正确的。下周甚至可能是正确的,但是在更新标准库之后一个月内不正确(例如应用错误修复)。其他实现可能不正确。
最后,有几个小问题。
首先,您的代码不完整,甚至无法以您描述的形式进行编译。在上面的讨论中,我假设您的代码实际上以
开头#include <iostream>
#include <cstdlib>
using namespace std;
其次,malloc()
和free()
是标准库中的函数。他们不是运营商。
答案 2 :(得分:2)
您对实际情况的分析是正确的;但是,程序不保证可靠地表现这种方式。在free(p)
&#34;之后*p
的每次使用都会引发未定义的行为&#34;。 (当您在没有先写入任何内容的情况下访问*r
和int main() {}
时也会发生这种情况。)未定义的行为更糟而不仅仅是产生不可预测的结果,并且更糟< / em>而不仅仅是可能导致程序崩溃,因为显式允许编译器假定引发未定义行为的代码永远不会执行。例如,编译器将您的程序视为与
.desktop
因为程序中没有控制流路径不会引起未定义的行为,所以必须是程序永远不会运行的情况!
答案 3 :(得分:0)
free()
释放堆内存以供OS重用。但是存储器地址中存在的内容不会被删除/删除。