静态分配的内存在其作用域结束后会发生什么?

3
void PrintArray()
{
  int a[4] = {4,3,1,5};
  for(int i=0; i<4; i++)
    cout<<a[i];
}

这个函数调用完成后,指针变量'a'所分配的内存和其指向的4个整数块会发生什么事情?它们会被释放掉还是会导致某种形式的内存泄漏?


2
这里的a不是指针,而是一个数组。数组有时会衰变为指针。 - avakar
另外,a 不是静态变量。它是自动变量。 - Mooing Duck
当函数返回时,a 会自动被销毁。没有内存泄漏。如果你的代码中有new或者malloc,那就需要担心内存泄漏。 - Neil Kirk
5个回答

3
a不是一个静态变量,它是一个自动变量。根据C99标准草案6.2.4对象的存储期第4段所述:“如果一个标识符的对象没有链接且没有使用static存储类说明符,则具有自动存储期。”
第3段中,它描述了static的生命周期为程序的生命周期,并在第5段中说明:
“对于这样一个没有可变数组类型的对象,它的生命周期从进入与其关联的块开始,直到以任何方式结束该块的执行。”
因此,对于自动变量,其生命周期延伸到其作用域,本例中a的作用域是函数PrintArray,与之相关联的存储在退出该作用域后被释放。
对于C ++,从标准草案中的3.7.3自动存储期第1段可以得到相关部分:
“显式声明为寄存器或未显式声明为静态或外部的块作用域变量具有自动存储期。这些实体的存储持续到它们创建它们的块退出。”

2

自动变量不是静态的,它们在作用域结束时(即函数结束时)被处理。 静态变量将持续存在,它将保留其值,即使在函数中调用它也是如此。 这里有一个关于extern/static变量的链接,了解更多详情。


1

内存不会泄漏。它没有在堆上分配。现在,这里可能涉及到2个不同的内存位置。

  1. { 4,3,1,5 } 初始化程序存储的位置。通常这样的初始化程序存储在数据段中。在嵌入式系统中,这可能是只读闪存。在个人电脑或其他设备上,这将只是一个使用您的程序映像(例如EXE)进行初始化并且不会被修改的RAM区域。函数退出后,它仍然存在。但这不是泄漏 - 只是您程序的内存占用量的一部分(有些人可能称之为静态内存)。
  2. PrintArray() 函数作用域中为 a[] 分配的堆栈内存。编译器所做的是分配一些堆栈空间,并从数据段中复制函数开头的值。通常情况下,这就是发生的情况,以便如果您修改了 a[] 中的任何元素,它只会影响该特定函数调用的该数组。当再次调用 PrintArray() 时,原始初始化程序未被修改,可供重复使用。如果由于先前调用而导致值突变,则后续对 PrintArray() 的调用初始化为除 { 4,3,1,5 } 之外的某些内容将是奇怪/意外的。但是,在此处您没有修改它,因此可能不会在堆栈上分配任何内容。您的情况可能有所不同。假设 a[] 确实驻留在堆栈上,则在函数退出时将自动释放(因此是 auto 变量)。

当然,发生的具体情况取决于您的编译器、链接器、设置(尤其是优化)和目标。


谢谢您的详细解释,但我主要关心的是分配给a的4个整数块。我想知道的是,这个4个整数块是否会被释放用于其他用途,还是一直停留在内存中直到程序结束。 - Jobin Jose

0
在C语言中,像a这样的自动对象会在声明它的代码块结束时被丢弃。

0
指针变量'a'和由'a'指向的4个整数块。
首先,我们需要澄清一个基本误解。'a'不是与4元素数组不同的单独指针变量;'a'就是这个4元素数组。'a'的地址和'a[0]'的地址是相同的。在大多数情况下,表达式'a'从类型为“4元素int数组”转换为“指向int的指针”,表达式的值是数组中第一个元素的地址。
回答这个问题,因为'a'是在块内声明且没有使用'static'关键字,所以它具有自动存储期,这意味着当您离开封闭作用域(在本例中是函数体)时,数组占用的内存将被释放。

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