理解栈、堆和内存管理

4
int *ip = new int[10];
for (int i = 0; i<10; i++)
    *(ip+i) = i;

myfun(ip);  // assume that myfun takes an argument of
            //   type int* and returns no result

delete [] ip;

上面的代码是我正在尝试学习堆栈和堆相关知识时使用的测试函数的一小部分。
我不确定正确的顺序是什么。
到目前为止,我已经做到了以下几点:
- 当指针ip被创建时,它指向一个新的int数组,大小为10,由于“new”声明而在堆上创建。 - 从0到9将添加到数组中。 - 现在将指针传递给myfun,这意味着myfun具有指向堆上相同内存空间的指针。 - delete []ip;删除在堆上分配给ip指针的内存。传递到myFun的指针现在指向无效内存。 - 一旦函数完成,ip变量将被删除,因为它只是函数本地变量。
请问是否有人能够澄清我是否正确,并纠正我哪里出错了?如果我之后继续使用ip,它会指向无效内存吗?

1
栈变量并非真正被删除,栈顶(esp)只是下移。下一个被调用的函数将再次将其上移,如此往复。 - mangusta
2
从概念上讲,变量被销毁,实际上是通过将堆栈指针返回到调用函数之前的位置来完成的。 - TartanLlama
4
现在传递给myFun的指针指向了空值,这有点含糊不清...该指针将继续保留相同的内存地址,但在分配一个仍然有效的指针值之前,无法对其进行解引用操作。 - Tony Delroy
2
另外,new自由存储区 上分配内存,而不是堆上,但这基本上是一个概念上的区别。 - TartanLlama
1
传递给 delete[] 的地址上的项目通常会一直保存在那里,直到另一次动态内存分配(另一个对于相同基础内存使用 new 或者 malloc 的调用)返回完全或部分重叠的内存区域(或者动态内存分配库本身决定将该内存用于某些内部管理信息)。除非分配库恰好从另一个 newmalloc 给您另一个指向它的指针,否则您不得再次访问它。在解引用之前应重新分配指针。 - Tony Delroy
显示剩余7条评论
3个回答

3

我认为一切都是正确的,关于以下小点我有一个小注记:

  • delete []ip;会删除分配给ip指针在堆上的内存。传递给myFun的指针现在指向了“无”。

不能保证指针指向“无”,通常建议(请参阅下面答案评论中的澄清)在调用delete后,将指针初始化为NULL,即ip = NULL,以确保指针指向“无”(而不是指向未分配的内存)。


2
一般来说,如果指针即将结束其生命周期(例如因为它在即将退出的作用域中,或者已经在析构函数中被删除...),我建议不要这样做。在这种情况下,将其设置为NULL会错误地暗示某些重要性/实用性,并且会显得冗长无意义。 - Tony Delroy

3
序列是正确的,除了一个点:

delete []ip; 释放了分配给 ip 指针的堆内存。传递给 myFun 的指针现在不再指向任何东西。

这个指针并不指向“nothing”(即在释放内存后没有设置为 nullptr0)。它只是指向同一个位置,该位置现在是已被应用程序标记为已释放的内存,因此不能再安全地访问。通过该指针访问内存会触发未定义行为
最后注意: myfun 可能按值或按引用获取指针。虽然存在差异,但您的句子仍然有效。

1

一切都是正确的。但要注意,调用delete并不会“删除”任何内容,而是释放先前分配的内存,这意味着您的指针包含了您不能使用的地址(对已释放的内存块进行解引用会导致未定义的行为)。对于堆栈变量也是如此,与您的本地变量相关联的内存没有被销毁,而是被释放,因此您不能尝试使用它。堆栈和堆只是两种具有相同基本操作(分配/释放)的内存管理方式。

因此,从技术上讲,您不能说您的指针指向任何东西,而是指向您无权使用的某些内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接