为啥不需要释放静态数组?

Posted

技术标签:

【中文标题】为啥不需要释放静态数组?【英文标题】:Why don't static arrays need to be freed?为什么不需要释放静态数组? 【发布时间】:2016-09-05 00:37:49 【问题描述】:

我想知道为什么不需要释放静态数组?我知道在创建动态数组时,例如

int *p;
p = malloc(10*sizeof(int));

我们必须使用以下方法释放分配的内存:

free(p);

并且对于函数中的静态数组,静态数组会在被调用函数完成后自动释放。

我不明白的是:当使用这样的函数返回静态数组时:

int *subFunc()
    static int a[5] = 1,2,3,4,5;
    return a;


int main()
    int *p;
    p = subFunc();

如果静态数组在执行完成后自动释放,那我们怎么还能正确访问静态数组的值呢?

【问题讨论】:

【参考方案1】:

如果静态数组在执行完成后自动释放,那我们怎么还能正确访问静态数组的值呢?

不,不是那样的。 static 变量在启动 main() 之前被初始化,它的生命周期是程序的整个执行过程。因此,它们可以从函数(在其中定义它们)中returned,并且仍然可以访问。它们不是本地(对函数而言),当函数完成执行时,它们的生命周期就会结束。

相关,引自C11,第 6.2.4 章

一个对象,其标识符在没有存储类说明符的情况下声明 _Thread_local,可以使用外部或内部链接,也可以使用存储类 说明符static,具有静态存储持续时间。它的生命周期是整个执行 程序及其存储的值仅在程序启动之前初始化一次。

关于函数内static 变量的范围,是的,它仅限于函数本身,如第 6.2.1 章所述,

[...] 如果声明符或类型说明符 声明标识符出现在块内或参数声明列表中 一个函数定义,标识符有块作用域,它终止于 关联块。 [...]

这意味着,很明显,您不能在subFunc() 之外使用数组a,因为asubFunc() 之外可见

但是,当您 return 数组时(返回数组会导致指向数组第一个元素的指针衰减,FWIW),因为 static 数组的生命周期是程序的整个执行,访问返回的指针(当然,在界限内)是完全有效和合法的。

【讨论】:

static locals 的行为与static globals 有点不同:它们不是在程序启动时初始化,而是when execution first passes their initialization point。 @Quentin 你确定 C 也是如此吗?你能链接一些参考资料吗? 显然我确实混淆了 C 和 C++ 规则。我的坏! @Quentin @Sourav 不过没关系,在到达初始化点之前,您无法访问函数本地 static。而在 C 中,static 初始化程序可能无论如何都没有副作用,因此您无法真正观察到它何时被初始化。 您不能在subFunc() 之外使用a,但我看不出有任何理由您不能使用指向a 的指针并在subFunc() 之外使用它。【参考方案2】:

静态变量即使在它们所在的块之后仍然存在 被定义终止。因此,一个静态变量的值 函数在重复的函数调用之间保留 功能。静态自动变量的范围与此相同 自动变量,即它是它所在的块的本地变量 定义;但是,分配的存储空间对于 程序的持续时间。静态变量可以在它们的 声明;但是,初始化程序必须是常量表达式, 并且初始化只在编译时完成一次,当内存是 分配给静态变量。 - source

当控制来自该函数时,不会释放静态数组或变量。

静态变量的

作用域对于声明它的函数是局部的,但它的生命周期是贯穿整个程序的。

【讨论】:

就在今天我听到有人说“不管是在函数内部,静态变量是永远的”。 @Agostino 当然,由于并非所有静态变量都被立即销毁,显然其中一些变量的 forever 值比其他变量更大。 :-)【参考方案3】:

并且对于子函数中的静态数组,静态数组会在调用的子函数完成后自动释放。

那不是真的。进入函数时不创建静态数组,离开时不销毁。

一个静态变量,以及其中的数据,真的很像一个全局变量!函数的唯一本地是 name。 (你会听到人们谈论变量的“范围”——这意味着“我可以在哪里使用名称来引用它。”)

所以当你在思考静态数组的寿命时,你可以在脑海中替换:

int *subFunc()
    static int a[5] = 1,2,3,4,5;
    return a;

int ONLY_USE_ME_INSIDE_SUBFUNC__a[5] = 1,2,3,4,5;  /* global variable */

int *subFunc()
    int * a = ONLY_USE_ME_INSIDE_SUBFUNC__a;  /* a is the same as the global */
    return a;

然后假装程序中没有其他人可以触及该全局变量。

【讨论】:

顺便说一句,一些编译器会将前者视为后者,但使用自动生成的名称,如 $STATIC$fd91a2e7$subFunc_a 可以保证不会与 C 文件中有效的任何内容冲突 [因为用户标识符不能包含美元符号]。【参考方案4】:

Static variables 在函数内部,通常用于在多次调用函数时维护函数范围内的一些数据。它们在 main() 之前初始化,它们的生命周期是程序的整个执行。因此,如果它们在退出函数后被释放,那将没有意义。如果你释放它们,你会在下次调用函数时崩溃,因为它们不会被引用。

【讨论】:

【参考方案5】:

我想知道为什么不需要释放静态数组?

    任何未被内存管理函数(malloc、calloc)分配的东西,例如int a[5],对于释放都不需要明确处理。

    静态变量,例如static int a[5] 可在本地范围内访问(它们在本地函数的后续调用之间保留其值)。它们正是为此目的在编译时创建的,它们具有程序生命周期,因此即使有可能,释放它们也不是合乎逻辑的考虑,这是不可能的

    其他答案都在巧妙地解释其他所有内容。

【讨论】:

以上是关于为啥不需要释放静态数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用静态数组释放内存?

为啥在 Objective-C 中执行 alloc 和 init 在单独的语句中会导致对象根据 Xcode 静态分析器被释放?

为啥数组会引起nvlink警告:入口函数的堆栈大小不能静态确定

为啥要保留静态变量?

为啥 C# 公共静态变量不需要实例化?

为啥大型静态数组会产生段错误而动态却不会? (C++)