为什么静态数组不需要被释放?

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

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();
}
如果静态数组在执行完毕后会自动释放,那么我们如何仍然正确地访问静态数组的值?
5个回答

45
如果静态数组在完成执行后自动释放,那么我们如何正确访问静态数组的值呢?不是这样的。静态变量会在开始 main() 之前初始化并且其生命周期为整个程序的执行期间。因此,它们可以从定义它们的函数中返回,并且仍然可以被访问。它们不是局部的(对于函数来说),在函数完成执行时不会失效。关于静态变量在函数内的作用域,它是局限于函数本身的,因此无法在 subFunc() 之外使用数组 a。但是,当你返回数组时(返回数组会导致衰减为数组第一个元素的指针),由于静态数组的生命周期为整个程序的执行期间,在边界内访问返回的指针是完全有效和合法的。

6
static 局部变量与 static 全局变量的行为有所不同:它们的初始化不是在程序启动时进行,而是在程序执行首次经过它们初始化的位置时进行 - Quentin
4
@Quentin,你确定C语言也是这种情况吗?你能否提供一些参考资料的链接? - Sourav Ghosh
2
显然我确实混淆了C和C++的规则。我的错! - Quentin
2
@Quentin @Sourav 不过,这并不太重要,因为在达到其初始化点之前,你无法访问函数内部的static。而且在C语言中,static的初始化器可能没有任何副作用,所以你实际上无法观察到它何时被初始化。 - Tavian Barnes
subFunc() 之外,你不能使用 a ,但我并没有看到任何理由你不能使用指向 a 的指针,并且在 subFunc() 之外使用它。 - Z boson
显示剩余2条评论

21
静态变量在定义它们的块终止后仍然存在。因此,函数中静态变量的值在对同一函数进行重复调用时保留。静态自动变量的作用域与自动变量相同,即局部于定义它的块; 但是,分配的存储器在程序的持续时间内变为永久。静态变量可以在其声明中初始化; 然而,初始化必须是常量表达式,并且初始化仅在编译时为静态变量分配内存时执行一次。 - source 静态数组或变量将不会在控制流离开该函数时被释放。
静态变量的作用域局限于声明它的函数,但其生命周期贯穿整个程序。

1
今天我听到有人说:“无论它是否在函数内部,静态变量都是永久的”。 - Agostino
2
@Agostino 当然,由于并非所有静态变量都会同时被销毁,因此显然有些变量比其他变量拥有更长的“永久性”值。 :-) - Frerich Raabe

11

对于子函数中的静态数组,当调用的子函数完成时,静态数组将自动释放。

这不是真的。静态数组不是在进入函数时创建的,离开函数时也不会被销毁。

静态变量及其内部数据实际上非常类似于全局变量!唯一本地化的是名称。(你会听到人们谈论变量的“作用域”-这意味着“我在哪里可以使用名称来引用它。”)

因此,在考虑静态数组的生命周期时,可以在心中替换:

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文件中的任何有效内容发生冲突,因为用户标识符中不能包含美元符号。 - supercat

3
我想知道为什么静态数组不需要被释放?
1. 不是由内存管理函数(如malloc、calloc)分配的任何东西,例如int a[5],不需要显式地释放。
2. 静态变量,例如static int a[5],用于在局部范围内访问(它们在后续调用局部函数之间保留其值)。它们在编译时创建,具有程序生命周期,因此即使可能释放它们,逻辑上也不需要释放它们。
3. 其他答案已经很好地解释了其他内容。

2

函数内的静态变量通常用于在多次调用函数时维护一些数据的作用域。它们在main()之前初始化,并且它们的生命周期是整个程序的执行期间。因此,如果在退出函数后释放它们,这是没有意义的。如果你释放它们,下一次调用该函数时会导致崩溃,因为它们将不被引用。


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