试图理解C ++中的堆栈和堆
我对C ++相当陌生,尽可能多地理解堆栈和堆的概念(或者至少和我需要知道的一样多)。 有些人倾向于说,初学者不应该打扰太多,但在我看来,内存泄漏或堆栈溢出很容易发生。 我一直在阅读一些东西,但我仍然有点困惑,不确定我是否正确。
这是我到目前为止...
1.堆:
堆是一个共享和动态分配的区域。 我们的流程的任何部分都可以通过正确的指针和内容知识(类型和长度)来访问。 如果我们尝试使用错误的指针(平凡的地址或指针释放)将导致分段错误。 访问比已分配的内容更大的内容也会导致分段错误(例如尝试读取比分配的数组大的数组)。 未使用的区域必须“手动”释放以避免内存泄漏
2.堆栈:
堆栈是分配参数和局部变量的内存部分。 这个堆栈的大小是有限的。 该堆栈作为LIFO(后进先出)工作。
假设堆栈是预定义大小的堆栈(堆栈大小)。 当我们定义局部变量时,它们被放入堆栈(进入bin),并且一旦范围发生变化(例如调用一个函数),在我们的bin中就会使用一个拼盘来防止访问前面的范围中定义的变量以及一个新的本地范围已创建。 一旦一个函数结束,所有的局部变量都被销毁并且我们仓中的盘片被移除(返回到前一个范围)。
示例:
void MyFunction()
{
int *HeapArray = new int[10];
// HeapArray is assigned 40 bytes from the heap
// *HeapArray is assigned 4 bytes from the stack in a 32 bit environment
int StackArray1[10];
// StackArray is assigned 40 bytes from the stack
int StackArray2[20];
// StackArray is assigned 80 bytes from the stack
HeapArray = StackArray2;
// segmentation fault because StackArray it too large
delete HeapArray;
// this will deallocate the area assigned in the heap
// omitting delete would result in memory leaks
// the pointer itself *HeapArray continues to exist in the stack
HeapArray = StackArray1;
// segmentation fault because HeapArray is pointing to deallocated memory
MyFunction();
// this will result in a stack overflow
}
问题:
Q1。 定义一个局部变量对于堆栈来说太大了,或者像我上面的例子那样有一个无限递归函数给了我一个分段错误。 为什么不这样说'堆栈溢出'? 是否因为堆栈“溢出到堆中”并产生分段错误?
Q2。 假设我为堆栈提供的bin和platters的例子:当使用extern
,内容被复制到最后一个盘片顶部的新范围,或者是创建了某种类型的指针?
你发布的代码充满了bug,但不仅仅是你在评论中列出的代码。 与此同时,普通的C风格数组是不可分配的。 因此,下面一行不会将右侧数组的内容复制到左侧数组中。
HeapArray = StackArray2;
C和C ++允许从数组到一个指向数组第一个元素的指针的隐式转换; 这通常被称为衰减到指向第一个元素的指针。 因此,上面的语句导致HeapArray
指针指向StackArray2
的开始。 然后,当你调用delete
对HeapArray
,你想delete
内存,这不是new
编辑。 这是未定义的行为,并会导致程序崩溃(如果幸运的话)。
除此之外,你还泄漏了你通过new
分配的内存,因为你现在失去了唯一指向那个内存的指针。
同样,下一个任务来HeapArray
被分配的地址StackArray1
到HeapArray
。 因为你只分配指针,所以在这行上没有错误; 该程序将继续执行正常(但由于前一次删除,您可能已经崩溃)。
回答你的问题 -
1 - 没有保证溢出堆栈或错误删除总是会以可预测的方式失败。 它也取决于你正在使用的编译器。 如果我注释掉MyFunction()
所有代码MyFunction()
除了递归调用自身),g ++ 4.8不会发出警告,并且会因分段错误而失败。 但是,VS2012发出警告
警告C4717:'MyFunction':在所有控制路径上递归,函数会导致运行时堆栈溢出
并在运行时声明失败
Test.exe中0x00062949未处理的异常:0xC00000FD:堆栈溢出(参数:0x00000001,0x00802FA4)
但是,这是在禁用优化的情况下。 启用优化后,程序将无限运行(包含两个编译器)。 这可能是因为代码足够小,以至于两个编译器都会将自我的递归调用替换为无限循环。 现在不会有堆栈溢出,但是你的程序永远不会终止。
2 - 全局变量(您extern
从另一个翻译单元访问的变量)不存储在堆栈中。 它们存储在与堆栈不同的内存实现定义区域中。
Q1。 发生的情况称为堆栈溢出,但效果是您要超出堆栈允许的内存,因此您尝试访问您无法访问的内容,因此从技术上讲它是一种分段错误。
Q2。 你的例子不适合,因为堆栈没有隐藏任何以前的内容,任何指向堆栈中更深的任何指针仍然有效,它不会被连续调用隐藏。 它被称为堆栈,因为它的行为像一个堆栈(分配的数据在堆栈顶部增长),但是下面的任何内容都只是内存,如果你持有一个指针,就可以合法访问它。
另外需要注意的是,调用堆栈还包含函数调用的激活记录,这些记录用于正确返回。
链接地址: http://www.djcxy.com/p/79107.html