我试图找出用于c中的变量的内存何时被释放。例如,何时可以在以下代码片段中释放整数i
?
int function()
{
int i = 1;
// do some things
return 0;
}
答案 0 :(得分:9)
在C中,与所有其他语言一样,词汇范围的变量(例如此处的i
)仅在其范围内有效 - i
的范围来自其声明到结束括号功能。当它们被释放时,通常没有指定,但在实际的C实现中,局部变量在调用堆栈上分配,并且一旦函数返回就重用它们的内存。
考虑类似
的内容int function()
{
int i; // beginning of i's scope
{
int j; // beginning of j's scope
...
} // end of j's scope
{
int k; // beginning of k's scope
...
} // end of k's scope
return 0; // all locals of the function are deallocated by the time it is exited
} // end of i's scope
范围确定何时可以通过名称访问变量,并且对于本地(auto
)变量,可以有效地访问其内容(例如,如果设置指向局部变量的地址的指针,则取消引用变量范围外的指针是未定义的行为)。解除分配是一个有点不同的问题......大多数实现在j或k的范围结束时都不会做任何事情来“解除分配”它们,尽管它们可能会为这两个变量重用相同的内存。当function
返回时,大多数实现将通过堆栈指针的单个减量“弹出”堆栈中的所有本地,以及返回地址,实际上“释放”它们的内存......尽管内存仍然存在就在堆栈上,准备“分配”到下一个被调用的函数。
请注意,您的问题的术语有些混淆......变量具有范围,但它是分配和释放的内存,而不是变量。有些变量甚至可能没有为它们分配任何内存,例如,它们是常量或从未在程序中使用过。并且如上所述仅分配或释放局部变量的内存...静态和文件范围变量的内存永远不会被释放,并且仅在加载程序时分配。还有其他内存 - 堆内存 - 由程序显式分配和释放(通过调用malloc / realloc / calloc / strdup / free等)。但是,虽然堆内存可以通过指针变量引用,但指针变量本身的内存只包含引用(内存地址),变量具有本地或静态/文件范围。
答案 1 :(得分:7)
当它超出范围时,它将被释放。由于它具有函数范围,因此在函数返回时会发生这种情况。
答案 2 :(得分:1)
i
。执行返回时会释放它。
答案 3 :(得分:1)
自动变量是C中作用域的本地变量:
范围基本上由'{''}'标记,因此当您在{}对内时,您就在范围内。当然,范围可以嵌套。
这就是为什么在旧的C标准中,必须在范围的顶部定义局部变量,因为它使得编写C编译器更容易(编译器会看到'{'然后是所有变量然后是语句)所以它知道它必须处理的变量。这在C99(我认为?)中有所改变,后来你可以在语句之间的任何地方定义变量。
当然,这可能非常有用:
int foo()
{
int k = 0; /* inside the scope of foo() function */
for(; k < 10; k++) { /* don't need k = 0; here we set it to zero earlier */
int i = 1; /* initialize inside the scope of the for loop */
i = i * 2; /* do something with it */
printf ("k = %d, i = %d\n", k, i);
}
#if 0
printf ("i = %d\n", i); /* would cause an unknown identifier error
* because i would be out of scope, if you changed
* #if 0 to #if 1
*/
#endif
return 0;
}
int main()
{
foo();
foo();
return 0;
}
请注意,在foo()
中循环迭代的所有时间i = 2
更有趣的一点是关键字static
如何修改变量的持久性。
int bar()
{
int k = 0; /* inside the scope of bar() function */
for(; k < 10; k++) { /* don't need k = 0; here we set it to zero earlier */
static int i = 1; /* initialize inside the scope of the for loop */
i = i * 2; /* do something with it */
printf ("k = %d, i = %d\n", k, i);
}
#if 0
printf ("i = %d\n", i); /* would cause an unknown identifier error
* because i would be out of scope, if you changed
* #if 0 to #if 1
*/
#endif
return 0;
}
int main()
{
foo();
foo();
return 0;
}
请注意更改并注意如何处理静态变量。
如果将关键字static放在int k = 0之前,for循环会发生什么; ?
C宏非常有用。有时您想要定义复杂的本地宏而不是速度和整体简单性的函数。在一个项目中我想操纵大位图,但使用函数执行'和''或''xor'操作有点痛苦。位图的大小是固定的,所以我创建了一些宏:
#define BMPOR(m1, m2) do { \
int j; \
for (j = 0; j < sizeof(bitmap_t); j++ ) \
((char *)(m1))[j] |= ((char *)(m2))[j]; \
} while (0)
do {} while(0)是一个有趣的技巧,让一个范围的块连接到if / for / while等没有问题,该块只执行一次(因为在结束时检查while)块),当编译器看到while(0)时,它只是删除循环;当然,这可以让你在结尾放一个分号,这样IDE和你(后来)就不会对它的含义感到困惑。
上面的宏用作:
int foo()
{
bitmap_t map_a = some_map(), map_b = some_other_map();
BITOR(map_a, map_b); /* or map_a and map_b and put the results in map_a */
}
这里的do {} while(0)允许本地范围包含局部变量j,for循环以及我可能需要的任何其他东西。
答案 4 :(得分:0)
当变量超出范围时,变量将被释放。在代码变量i
将在执行return 0
语句后被释放。
您可以在变量范围here