void PrintArray()
{
int a[4] = {4,3,1,5};
for(int i=0; i<4; i++)
cout<<a[i];
}
该函数调用完成后,分配给指针变量“a”和“a”指向的 4 整数块的内存究竟会发生什么?块和指针变量的内存是否被取消分配,还是会造成某种内存泄漏?
void PrintArray()
{
int a[4] = {4,3,1,5};
for(int i=0; i<4; i++)
cout<<a[i];
}
该函数调用完成后,分配给指针变量“a”和“a”指向的 4 整数块的内存究竟会发生什么?块和指针变量的内存是否被取消分配,还是会造成某种内存泄漏?
a
不是静态变量它是一个automatic
变量,来自草案 C99 标准部分6.2.4
对象存储持续时间第 4 段说:
其标识符声明为没有链接且没有存储类说明符 static 的对象具有自动存储持续时间。
在第 3 段中,它将生命周期描述static
为程序的生命周期,在第 5 段中说:
对于这样一个没有可变长度数组类型的对象,它的生命周期从进入与其关联的块开始,直到该块的执行以任何方式结束。[...]
所以换句话说,对于一个自动变量来说,它的生命周期延伸到它的作用域,在这种情况下,a
s 作用域是函数PrintArray
,并且与它关联的存储在该作用域退出后被释放。
对于 C++,标准草案中的相关部分是3.7.3
自动存储持续时间第 1 段说:
显式声明的块范围变量 register 或未显式声明的 static 或 extern 具有自动存储持续时间。这些实体的存储一直持续到创建它们的块退出。
自动变量不是静态的,它们在其作用域的末尾(在函数的末尾)被处理掉。一个静态变量会持续存在,它会保持它的值,即使它在函数中被调用。这是有关外部/静态变量的链接以获取更多详细信息。
内存不会泄漏。它不在堆上分配。现在,这里可能涉及 2 个不同的内存位置。
{ 4,3,1,5 }
存储初始化程序的位置。通常,像这样的初始化程序存储在数据段中。在嵌入式系统中,这可能是只读闪存。在 PC 或其他任何设备上,这将只是一个 RAM 区域,它使用您的程序映像(例如 EXE)进行初始化,并且不会被修改。函数退出后,它仍然存在。但这不是泄漏——只是程序内存占用的一部分(有些人可能会说是静态内存)。a[]
在PrintArray()
函数范围内分配的堆栈内存。编译器所做的是分配一些堆栈空间,然后从数据段复制函数开头的值。这通常是发生的事情,因此如果您修改 中的任何元素a[]
,它只会影响该特定函数调用的数组。当PrintArray()
再次调用时,原始初始化程序未修改并可重用。如果后续调用PrintArray()
初始化为某些东西,除了{ 4,3,1,5 }
由于先前的调用改变了值,那将是奇怪/出乎意料的。但是,您没有在此处对其进行修改,因此优化可能不会在堆栈上分配任何东西是合理的。YMMV。假设a[]
确实驻留在堆栈上,它将auto
在函数退出时自动释放(因此是变量)。当然,究竟发生了什么取决于您的编译器、链接器、设置(尤其是优化)和目标。
指针变量 'a' 和 'a' 指向的 4 整数块
首先,我们需要澄清一个基本的误解。 a
不是与 4 元素数组不同的单独指针变量;a
是4 元素数组。的地址a
和地址a[0]
是一回事。大多数情况下,表达式 a
从“四元素数组int
”类型转换为“指针int
”,表达式的值是数组中第一个元素的地址。
为了回答这个问题,由于a
在块中声明并且没有static
关键字,它具有自动存储持续时间,这意味着当您离开封闭范围(在本例中为函数体)时,数组占用的内存将被释放。
在 C 中,自动对象 likea
在已声明的块的出口处被丢弃。