我的问题:
int* x = new int;
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x;
delete p;
cout << p <<"\n";
我纯粹是自己写这篇文章来理解指针并理解(也迷失)动态new
和delete
。
我的XCode可以编译程序并返回以下结果:
0x100104250
0x0
0x100104250
我知道我只能在动态分配的内存上调用delete。
但是,我在上述程序中调用p
上的删除并编译。
有人可以向我解释一下吗?
为什么我可以删除p
?
此外,我发现程序是否更改为以下内容:
int* x = new int;
int* p;
cout << p <<"\n";
delete p;
cout << p <<"\n";
然后我的Xcode再次编译并返回给我:
0x0
0x0
Program ended with exit code: 0
现在,我完全迷失了:(。
有人可以解释一下吗?
为什么我可以删除p
,因为它与x
无关?
由于Xcode编译成功,我认为上述两个程序对于计算机是正确的。 但是,我认为它再次只是在动态分配的内存上调用删除&#34;。 或者,我可能还没有完全理解什么是指针以及什么是动态分配的内存。 我在线搜索时发现了这个post。 但我不认为这就像我的情况。
请帮帮我。
我想再问一个问题。关于二叉搜索树的代码是here。 从第28行到第32行,它涉及删除一个孩子的节点。 我把这部分代码放在这里,万一网页链接不起作用。
else if(root-&gt; left == NULL){ struct Node * temp = root; root = root-&gt; right; 删除临时; }
正是这些代码引导我问上面关于指针的问题。 按照这篇文章给出的答案。 以下列方式理解代码是否正确?
我不能先将root的父节点链接到root的右子节点。 然后删除根节点,因为根节点下的子树也将被删除。 所以我必须创建一个临时指针,指向由root指向的内存槽。 然后我将root的父节点链接到root的右子节点。 现在,我可以安全地删除&#34; root&#34;所指向的内存插槽(即temp,因为它们都指向同一个内存)。 通过这种方式,我释放内存并保持父和子之间的链接。 此外,临界温度仍然存在,仍然指向&#34;那个&#34;内存插槽。 我应该在删除后将其设置为NULL吗?
提前再次感谢大家。
耀峰
答案 0 :(得分:2)
是的,您只能在通过delete
分配的内存上调用new
。请注意,它是内存的地址(指针的值),而不是存储指针的变量。所以,你的第一个代码:
int* x = new int; //(A)
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x; //(B)
delete p; //(C)
cout << p <<"\n"; //(D)
行(A)在某个地址(示例输出中为0x100104250
)动态分配内存,并将此地址存储在变量x
中。内存通过new
分配,这意味着最终必须在地址delete
上调用0x100104250
。
行(B)将地址0x100104250
(指针x
的值)分配给指针p
。然后,行(C)调用delete p
,这意味着“释放p
指向的内存”。这意味着它会在地址delete
上调用0x100104250
,一切都很顺利。地址0x100104250
的内存是通过new
分配的,因此未通过delete
正确分配。您使用其他变量存储值的事实不起作用。
Line(D)只打印出指针的值。 delete
作用于指针所指向的内存,而不是指针本身。指针的值保持不变 - 它仍指向相同的内存,不再分配内存。
第二个示例有所不同 - 当delete p
未初始化为任何内容时,您正在调用p
。它指向一个随机的内存,因此在其上调用delete
当然是非法的(从技术上讲,它具有“未定义的行为”,并且很可能会崩溃)。
在您的特定示例中,您似乎正在运行调试版本,并且如果您不自己初始化它们,则编译器会“帮助”将局部变量初始化为0。所以它实际上导致你的第二个例子没有崩溃,因为在空指针上调用delete
是有效的(并且什么都不做)。但该程序实际上有一个错误,因为局部变量通常不会隐式初始化。
答案 1 :(得分:1)
p = x;
这会使p
包含与x
相同的值(p
将指向与x
相同的对象)。所以基本上当你说
delete p;
它对p
引用的地址执行删除操作,该地址与x
相同。因此,这完全有效,因为该地址所引用的对象是使用new
分配的。
第二种情况: -
同时你的指针p
由编译器设置为NULL pointer
(你不应该依赖于此)。所以删除该指针是安全的。如果不是NULL指针,你可能会看到崩溃。
答案 2 :(得分:1)
好的,让我们来看看&#34;删除&#34;的文档。运营商。根据{{3}}:
由delete-expressions调用以释放先前为单个对象分配的存储空间。除非ptr是空指针或者是先前从operator new(size_t)或operator new(size_t,std :: nothrow_t)的标准库实现获得的指针,否则此函数的标准库实现的行为是未定义的。
所以会发生以下情况:您正在调用new运算符,它为内存中的int变量分配sizeof(int)字节。内存中的那部分由指针x引用。然后创建另一个指针p,它指向相同的内存地址。当您调用delete时,将释放内存。 p和x仍然指向相同的内存地址,除了该位置的值现在是垃圾。为了使这更容易理解,我按如下方式修改了代码:
#include <iostream>
using namespace std;
int main() {
int * x = new int; // Allocate sizeof(int) bytes, which x references to
*x = 8; // Store an 8 at the newly created storage
cout << x << " " << *x << "\n"; // Shows the memory address x points to and "8". (e.g. 0x21f6010 8)
int * p; // Create a new pointer
p = x; // p points to the same memory location as x
cout << p << " " << *p << "\n"; // Shows the memory address p points to (the same as x) and "8".
delete p; // Release the allocated memory
cout << x << " " << p << " "
<< *x << " " << *p << "\n"; // p now points to the same memory address as before, except that it now contains garbage (e.g. 0x21f6010 0)
return 0;
}
跑完后,我得到了以下结果:
0x215c010 8
0x215c010 8
0x215c010 0x215c010 0 0
所以请记住,通过使用delete释放内存,但指针仍指向同一地址。这就是为什么以后将指针设置为NULL通常也是一种安全的做法。希望现在更有意义了: - )
答案 3 :(得分:0)
在回答之前,您需要了解以下几点。
delete
指针,需要就不会被分配0
。它
可以是任何东西。0
或NULL
。但是,我在上面的程序中调用了删除p并编译。
有人可以向我解释一下吗?为什么我要删除p?
这是因为您通过new
分配了由x
分配的内存地址。 (p = x;
)x
(或p
)是有效的内存位置,可以删除。
现在x
被称为Dangling pointer。因为它指向的内存不再有效。删除后访问x
是未定义的行为。
有人可以解释一下这个吗?为什么我可以删除p,因为它与x无关?
这是因为您的p
被赋值为0.因此您正在逃避未定义的行为。但是,无法保证未初始化的指针的值为0
或NULL
。在这一点上它似乎工作正常,但你在这里涉及未定义的行为。
答案 4 :(得分:0)
delete / free关键字用于从存储位置清空存储的值。如果不使用指针,则可以将值重新分配为NULL或只是让它们超出范围。
如果使用指针超出范围而不删除值,请小心使用指针。它将导致内存泄漏。因为该存储块的该部分不再可用。我们丢失了地址,因为我们属于不同的范围。