简体   繁体   English

指针和动态内存分配

[英]pointer and dynamic memory allocation

My question:我的问题:

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

I wrote this purely by myself to understand the pointer and to understand (also get lost in) the dynamic new and delete .我写这个纯粹是为了理解指针和理解(也迷失在)动态的newdelete

My XCode can compile the program and return the following results:我的 XCode 可以编译程序并返回以下结果:

 0x100104250
 0x0
0x100104250

I know I can only call delete on dynamically allocated memory.我知道我只能在动态分配的内存上调用 delete 。 However, I called delete on p in the above program and it compiles.但是,我在上面的程序中调用了p上的 delete 并编译了它。

Could anyone explain this to me?有人可以向我解释一下吗? Why could I delete p ?为什么我可以删除p

Moreover, I found if the program changes to the following:此外,我发现程序是否更改为以下内容:

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

Then my Xcode again compiles and returns me:然后我的 Xcode 再次编译并返回我:

 0x0
 0x0
 Program ended with exit code: 0

and now, I got completely lost:(. Could anyone please explain me this ? Why I could delete p since it has nothing to with x ?现在,我完全迷失了:(。谁能给我解释一下?为什么我可以删除p因为它与x无关?


Since Xcode compiles successfully, I assume the above two programs are correct for computer.由于Xcode编译成功,我假设以上两个程序对计算机是正确的。 However, I think it is again the statement of "only call delete on dynamic allocated memory".但是,我认为这又是“仅在动态分配的内存上调用删除”的说法。 Or probably, I didn't fully understand what is pointer and what is dynamic allocated memory.或者可能,我没有完全理解什么是指针,什么是动态分配的内存。 I found this post when I searched online.我在网上搜索时发现了这个帖子 But I don't think it is like my case.但我认为这不像我的情况。

Please help me out.请帮帮我。


I would like to ask one more question.我还想问一个问题。 The code is here about binary search tree.该代码是在这里大约二叉搜索树。 From line 28 to 32, it deals with deleting a node with one child.从第 28 行到第 32 行,它处理删除一个有一个子节点的节点。 I put this part of code here, in case the weblink does not work.我把这部分代码放在这里,以防万一网络链接不起作用。

else if(root->left == NULL) { struct Node *temp = root; else if(root->left == NULL) { struct Node *temp = root; root = root->right;根=根->右; delete temp;删除温度; } }

It is these codes leading me ask the above the question regarding pointer.正是这些代码引导我问上述有关指针的问题。 Following the answer given by this post.按照这篇文章给出的答案。 Is it correct to understand the code in the following way?按照以下方式理解代码是否正确?

I cannot firstly link the parent node of root to right child of root.我不能首先将 root 的父节点链接到 root 的右子节点。 and then delete the root node, as the subtree beneath the root node will also be deleted.然后删除根节点,因为根节点下面的子树也将被删除。 So I must create a temp pointer, pointing to the memory slot, which is pointed to by root.所以我必须创建一个临时指针,指向 root 指向的内存槽。 Then I link the parent node of root to right child of root.然后我将根的父节点链接到根的右子节点。 and now, I can safely delete the memory slot pointed by "root", (ie temp as they both point to the same memory).现在,我可以安全地删除“root”指向的内存插槽(即临时,因为它们都指向同一内存)。 In this way, I release the memory and also keep the link between parent and children.这样,我释放了记忆,也保持了父子之间的联系。 In addition, the temp is still there and still points to "that" memory slot.此外,温度仍然存在并且仍然指向“那个”内存插槽。 Should I set it to NULL after deletion?删除后我应该将其设置为NULL吗?

Thank you all again in advance.再次感谢大家。

Yaofeng耀峰

Yes, you can only call delete on memory which was allocated via new .是的,您只能在通过new分配的内存上调用delete Notice that it's the address of the memory (the value of the pointer) which matters, and not the variable storing the pointer.请注意,重要的是内存地址(指针的),而不是存储指针的变量。 So, your first code:所以,你的第一个代码:

int* x = new int; //(A)
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x;  //(B)
delete p;  //(C)
cout << p <<"\n"; //(D)

Line (A) allocates memory dynamically at some address ( 0x100104250 in your example output) and stores this address in variable x .第 (A) 0x100104250某个地址(示例输出中的0x100104250 )动态分配内存并将此地址存储在变量x The memory is allocated via new , which means that delete must eventually be called on address 0x100104250 .该内存通过分配new ,这意味着delete最终必须在地址称为0x100104250

Line (B) assigns the address 0x100104250 (value of pointer x ) into the pointer p .行 (B) 将地址0x100104250 (指针x值)分配给指针p Line (C) then calls delete p , which means "deallocate the memory pointed to by p ."行 (C) 然后调用delete p ,这意味着“释放p指向的内存”。 This means it calls delete on address 0x100104250 , and all is well.这意味着它在地址0x100104250上调用delete ,一切都很好。 The memory at address 0x100104250 was allocated via new , and so is not correctly allocated via delete .地址0x100104250处的内存通过new分配的,因此没有通过delete正确分配。 The fact that you used a different variable for storing the value plays no role.您使用不同的变量来存储值这一事实不起作用。

Line (D) just prints out the value of the pointer.第 (D) 行只是打印出指针的值。 delete acts on the memory to which a pointer points, not on the pointer itself. delete作用于指针指向的内存,而不是指针本身。 The value of the pointer stays the same - it still points to the same memory, that memory is just no longer allocated.指针的值保持不变 - 它仍然指向相同的内存,只是不再分配该内存。


The second example is different - you're calling delete p when p was not initialised to anything.第二个示例不同 - 当p未初始化为任何内容时,您正在调用delete p It points to a random piece of memory, so calling delete on it is of course illegal (technically, it has "Undefined Behaviour", and will most likely crash).它指向一块随机内存,因此对其调用delete当然是非法的(从技术上讲,它具有“未定义行为”,并且很可能会崩溃)。

It seems that in your particular example, you're running a debug build and your compiler is "helpfully" initialising local variables to 0 if you don't initialise them yourself.似乎在您的特定示例中,您正在运行调试版本,并且您的编译器“有帮助地”将局部变量初始化为 0,如果您不自己初始化它们。 So it actually causes your second example to not crash, since calling delete on a null pointer is valid (and does nothing).所以它实际上导致你的第二个例子不会崩溃,因为在空指针上调用delete是有效的(并且什么都不做)。 But the program actually has a bug, since local variables are normally not initialised implicitly.但该程序实际上有一个错误,因为局部变量通常不会隐式初始化。

p = x;

This would make p contain same value as x ( p would point to same object as x ).这将使p包含与x相同的值( p将指向与x相同的对象)。 So basically when you say所以基本上当你说

delete p;

Its doing delete on the address referred to by p which is same as that of x .它对p引用的地址进行删除,与x的地址相同。 Hence this is perfectly valid as object referred to by that address is allocated using new .因此,这是完全有效的,因为该地址引用的对象是使用new分配的。

Second case :-第二种情况:-

Co-incidently your pointer p is set by compiler as a NULL pointer ( You should not depend on this).巧合的是,您的指针p被编译器设置为NULL pointer (您不应该依赖于此)。 So deleting that pointer is safe.所以删除那个指针是安全的。 Had that not been a NULL pointer you would have possibly seen a crash.如果那不是 NULL 指针,您可能会看到崩溃。

Ok, let's take a look at the documentation for the "delete" operator.好的,让我们看看“删除”操作符的文档。 According to http://en.cppreference.com/w/cpp/memory/new/operator_delete :根据http://en.cppreference.com/w/cpp/memory/new/operator_delete

Called by delete-expressions to deallocate storage previously allocated for a single object.由删除表达式调用以释放先前为单个对象分配的存储空间。 The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new(size_t) or operator new(size_t, std::nothrow_t).此函数的标准库实现的行为是未定义的,除非 ptr 是空指针或者是先前从 operator new(size_t) 或 operator new(size_t, std::nothrow_t) 的标准库实现获得的指针。

So what happens is the following: you are calling the new operator, which allocates sizeof(int) bytes for an int variable in memory.所以会发生以下情况:您正在调用 new 运算符,它为内存中的 int 变量分配 sizeof(int) 字节。 That part in memory is referenced by your pointer x.内存中的那部分由您的指针 x 引用。 Then you create another pointer, p, which points to the same memory address.然后创建另一个指针 p,它指向相同的内存地址。 When you call delete, the memory is released.当你调用 delete 时,内存被释放。 Both p and x still point to the same memory address , except that the value at that location is now garbage. p 和 x 仍然指向相同的内存地址,只是那个位置的现在是垃圾。 To make this easier to understand, I modified your code as follows:为了更容易理解,我修改了你的代码如下:

#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;
}

After running, I got the following results:运行后,我得到以下结果:

0x215c010 8
0x215c010 8
0x215c010 0x215c010 0 0

So remember, by using delete you release the memory, but the pointer still points to the same address.所以请记住,通过使用 delete 释放内存,但指针仍然指向相同的地址。 That's why it's usually a safe practice to also set the pointer to NULL afterwards.这就是为什么之后将指针设置为 NULL 通常是一种安全的做法。 Hope this makes a bit more sense now :-)希望这现在更有意义:-)

Before the answers, you need to understand the following points.在回答之前,您需要了解以下几点。

  1. once you delete a pointer, it need not be assigned with 0 .一旦delete了一个指针,就不需要为它分配0 It can be anything.它可以是任何东西。
  2. You can delete a 0 or NULL without any harm.您可以删除0NULL而不会有任何伤害。
  3. Undefined behavior is one in which anything could happen.未定义行为是一种任何事情都可能发生的行为。 The program might crash, it might work properly as if nothing happened, it might produce some random results, etc.,程序可能会崩溃,它可能会正常工作,好像什么也没发生,它可能会产生一些随机结果,等等,

However, I called delete on p in the above program and it compiles.但是,我在上面的程序中调用了 p 上的 delete 并编译了它。

Could anyone explain this to me?有人可以向我解释一下吗? Why could I delete p?为什么我可以删除p?

That is because you assign the address of memory allocated by new via x .那是因为您通过x分配了new分配的内存地址。 ( p = x; ) x ( or p ) is a valid memory location and can be deleted. ( p = x; ) x ( 或p ) 是有效的内存位置,可以删除。

Now x is called a Dangling pointer .现在x被称为一个悬空指针 Because it is pointing to a memory that no longer valid.因为它指向一个不再有效的内存。 Accessing x after deleting is undefined behavior.删除后访问x是未定义的行为。

Could anyone please explain me this ?谁能给我解释一下? Why I could delete p since it has nothing to with x?为什么我可以删除 p 因为它与 x 无关?

This is because your p is assigned with 0. Hence you are getting away with undefined behavior.这是因为您的p被分配了 0。因此您正在摆脱未定义的行为。 However it is not guaranteed that your uninitialized pointer will have a value of 0 or NULL .但是,不能保证未初始化的指针的值为0NULL At this point it seems to work fine, but you are wading through undefined behavior here.在这一点上,它似乎工作正常,但是您在这里遇到了未定义的行为。

delete/free keyword is used to empty the stored value from the memory location. delete/free 关键字用于从内存位置清空存储的值。 if we dont use pointers we have the reassign the value to NULL or just let them go out of scope.如果我们不使用指针,我们可以将值重新分配为 NULL 或让它们超出范围。

Be careful using pointers, if we go out of scope using pointers without deleting the value.小心使用指针,如果我们在不删除值的情况下使用指针超出范围。 It will create memory leak.它会造成内存泄漏。 because that portion of the memory block is not usable anymore.因为那部分内存块不再可用。 And we lost the address because we are in different scope.我们丢失了地址,因为我们在不同的范围内。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM