指针和动态内存分配

时间:2014-12-08 08:11:01

标签: c++ pointers

我的问题:

int* x = new int;
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x;
delete p;
cout << p <<"\n";

我纯粹是自己写这篇文章来理解指针并理解(也迷失)动态newdelete

我的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吗?

提前再次感谢大家。

耀峰

5 个答案:

答案 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)

在回答之前,您需要了解以下几点。

  1. 一旦你delete指针,需要就不会被分配0。它 可以是任何东西。
  2. 您可以毫无伤害地删除0NULL
  3. 未定义的行为是任何事情都可能发生的行为。该 程序可能崩溃,它可能正常工作,好像什么也没发生, 它可能产生一些随机结果等,
  4.   

    但是,我在上面的程序中调用了删除p并编译。

         

    有人可以向我解释一下吗?为什么我要删除p?

    这是因为您通过new分配了由x分配的内存地址。 (p = x;x(或p)是有效的内存位置,可以删除。

    现在x被称为Dangling pointer。因为它指向的内存不再有效。删除后访问x是未定义的行为。

      

    有人可以解释一下这个吗?为什么我可以删除p,因为它与x无关?

    这是因为您的p被赋值为0.因此您正在逃避未定义的行为。但是,无法保证未初始化的指针的值为0NULL。在这一点上它似乎工作正常,但你在这里涉及未定义的行为。

答案 4 :(得分:0)

delete / free关键字用于从存储位置清空存储的值。如果不使用指针,则可以将值重新分配为NULL或只是让它们超出范围。

如果使用指针超出范围而不删除值,请小心使用指针。它将导致内存泄漏。因为该存储块的该部分不再可用。我们丢失了地址,因为我们属于不同的范围。