回到前面:
什么是静态变量?
具有 static 存储持续时间的对象在程序第一次启动时为其分配了存储空间,并且该存储空间一直保留到程序退出。如果满足以下条件,则对象具有static 存储持续时间:
- 它的标识符是在文件范围内声明的(在任何函数的主体之外);或
- 它的标识符是用
static关键字声明的
例子:
#include <stdio.h>
int g_var; // static storage duration
void foo( void )
{
static int s_var = 10; // static storage duration
int l_var = 10; // auto storage duration
printf( "g_var = %d, s_var = %d, l_var = %d\n", g_var++, s_var++, l_var );
}
在这个sn-p中,g_var和s_var都有static的存储持续时间; g_var 因为它是在文件范围内声明的,s_var 因为它是用 static 关键字声明的。凭借static 的存储持续时间,g_var 被隐式初始化为 0。请注意,s_var 在程序启动时被初始化一次 - 它不会被重新- 在后续调用foo 时初始化为10。因此,每次调用foo,输出将是
g_var = 0, s_var = 10, l_var = 10
g_var = 1, s_var = 11, l_var = 10
g_var = 2, s_var = 12, l_var = 10
...
l_var 具有 auto 存储期限 - 它的生命周期仅限于 foo 函数的生命周期。每次调用foo 时,l_var 的 new 实例的存储空间会在函数入口处分配和初始化,并在函数退出时释放。这很重要 - 当foo 退出时,l_var 不再存在,因此当foo 返回时,任何指向它的指针都将变为无效1.
这就是为什么你不能做类似的事情
int * bar( void )
{
int array[N];
...
return array;
}
因为一旦bar 退出,array 不再存在,并且返回的指针是无效。
现在,解决此问题的一种方法是将数组声明为 static:
int * bar( void )
{
static int array[N];
...
return array;
}
在这种情况下,array 在函数退出时并没有消失,所以指针仍然有效。
不过……
这会产生其他问题。只创建了一个array 的实例,它包含另一个调用bar 写入它的最后内容。代码不再是重入;它不能在执行中被安全地中断,然后在第一次调用完成之前被另一个函数调用。创建一个static 数组只是为了您可以干净地返回一个指向它的指针通常是错误的答案。
要么将目标数组作为参数传递给函数:
void foo( int *array, size_t arraySize )
{
...
array[i] = some_value;
...
}
或动态地分配一个数组并返回指向它的指针:
int * bar( void )
{
int *array = malloc( sizeof *array * N );
if ( array )
{
// initialize array contents
}
return array;
}
这样做的问题是,当您完成时,其他人负责释放该内存。
“函数返回指针”是否意味着它正在返回指针指向的内存地址?
函数返回一个指针的值,它是另一个对象的地址。在上面的代码中,bar 返回 表达式 array 的值,结果是array 的第一个元素的地址。
在上述bar 的第二种情况下,返回的值等于&array[0]。
我们将如何取消引用它?
您可以通过两种方式取消引用指针 - 使用 * 取消引用运算符,或使用 [] 下标运算符。
下标操作a[i]定义为*(a + i) - 给定地址a,从a 偏移i 元素(不是字节)并取消引用结果。因此,您可以获取从bar 返回的指针并对其执行以下操作:
int *p = bar();
printf( "p[0] = %d\n", *p );
printf( "p[0] = %d\n", *(p + 0) );
printf( "p[0] = %d\n", p[0] );
那么,这是否意味着数组和指针是一回事? 没有。数组不是指针;然而,在大多数情况下,数组表达式(即“N-element array of T”类型的表达式)将被转换(“decay”)为指针表达式(“pointer to T")。
- 很明显,
l_var占用的内存位置还存在,所以指针的值不会突然变成垃圾什么的;但是,该内存位置现在可供其他东西使用,如果您尝试读取或写入该位置,则可能会导致问题。