【问题标题】: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();
}

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

【问题讨论】:

    标签: c scope static return-value lifetime


    【解决方案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】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2012-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多