C++ 为什么动态内存允许在运行时操纵数组?
这只是“语言就是这样工作的”问题之一吗编辑: 为什么动态内存允许在运行时分配数组大小? 为什么我不能使用从堆栈调用的变量,而不是从堆调用的变量? 它们都是变量,其中一个只是从不同的位置调用,必须手动释放和创建。在堆栈中创建的变量可以C++ 为什么动态内存允许在运行时操纵数组?,c++,c,memory,dynamic,C++,C,Memory,Dynamic,这只是“语言就是这样工作的”问题之一吗编辑: 为什么动态内存允许在运行时分配数组大小? 为什么我不能使用从堆栈调用的变量,而不是从堆调用的变量? 它们都是变量,其中一个只是从不同的位置调用,必须手动释放和创建。在堆栈中创建的变量可以 在运行时更改,对吗 使用堆的主要原因不是您可以使用不同数量的堆。它的主要用途是允许内存在特定函数完成后保持 C99和后来的标准(但不是C++),虽然我相信一些编译器(G++)确实有扩展,允许它至少在函数中允许“可变长度数组”,但是像固定大小的数组一样,函数结束时它
在运行时更改,对吗 使用堆的主要原因不是您可以使用不同数量的堆。它的主要用途是允许内存在特定函数完成后保持
C99和后来的标准(但不是C++),虽然我相信一些编译器(G++)确实有扩展,允许它至少在函数中允许“可变长度数组”,但是像固定大小的数组一样,函数结束时它们就“消失”。p> <>在C++标准中,所有数组在编译时必须有一个已知的(常数)长度。您必须使用堆来创建非恒定长度(编译时已知)的内容。这就是“语言的工作方式”
话虽如此,也有一个合理的理由。堆栈空间非常有限,事实上,耗尽堆栈是非常“危险”的,因为程序对此无能为力——它崩溃了,并且没有安全/合理的恢复方法。可以处理HEAPHOLL的运行(抛出C++异常,但至少程序可以显示一些合理的错误消息,并且可能以某种方式继续,即使它在HEAPHORE中运行时它试图做的不成功)。p> 当然,“C++方法”不是编写手动操作数组大小的代码,而是使用预定义的容器类型之一,例如std::vector
等等
编辑
请注意,一旦从堆中分配了一个数组,它将保持分配时的大小。改变其大小的方法是为第二个数组分配另一块不同大小的内存,然后将“旧”数组的内容复制到“新”数组中——只要这样做,代码就只能看到数组地址[指向第一个元素的指针]的“当前”值,没有人会知道它不是同一个数组
为什么我不能使用从堆栈调用的变量,而不是从堆调用的变量
堆分配使您能够更好地控制内存
此外,在堆栈变量方面也存在局限性
//警告:仅适用于PC,对于我不熟悉的其他体系结构可能不适用。(mips、摩托罗拉68000等基本上与x86无关的任何产品) 在堆栈中创建的变量可以在运行时更改,对吗 它们的大小不能改变
int main(int argc, char** argv){
char buffer[1024*1024*64];
buffer[0] = 0;
return 0;
}
如果在windows上使用默认设置编译,该程序将崩溃,在linux上也会崩溃。这是因为32位windows上的默认堆栈大小为1MB,32位linux上的默认堆栈大小为8MB(不过,系统可能会使用ulimit
)进行更改),而64MB的数组无法放入堆栈中为了理解为什么会有这样的限制,你需要从C++中退一步,学习一点汇编。试着找一本书,介绍段(数据/代码/堆栈),解释函数返回地址的存储位置,最好告诉您有关保护模式的内容。这应该会有帮助
当然,有一点问题。汇编知识只对特定系列的CPU有用。不同的CPU与C++编译器可以使用不同的规则。 --更新-- 为什么动态内存允许在运行时分配数组的大小 根据拱门的不同,堆栈大小可能或多或少是固定的。您为堆栈保留了一些内存区域,比如地址0x00100000..0x00200000,堆栈上的所有变量都将位于该区域的某个位置。新变量的位置由(若我没记错的话)“堆栈指针”确定,它沿着CPU确定的方向移动。在堆栈上添加新变量时,堆栈指针按大小变量移动(移动方向由CPU决定),变量将位于新旧内存位置之间的地址中。因为堆栈空间可以被限制,并且因为变量是相邻的(加上函数返回地址也存储在堆栈上),所以不能突然在其中间阻塞2GB数组。主要的问题实际上不是大小有限,而是变量彼此相邻 现在,堆不同了。从理论上讲,堆分配可以从整个地址空间中返回任何地址,但实际上某些地址将被保留(例如,在32位窗口中,整个4GB空间中只有2..3GB可用)。因为您有更多的可用空间,而且分配的块不必相邻,所以您可以自由分配大数组,甚至(理论上)调整它们的大小(实际上,像realloc这样的函数可能只是创建新数组,将旧内容复制到新数组中,然后杀死旧数组) 请注意,还有其他隐藏的详细信息。例如,堆分配函数返回给您的地址不是物理地址,而是虚拟地址