5

我试图找出用于 c 中变量的内存何时被释放。i例如,以下代码片段中的整数何时被释放?

int function()
{
  int i = 1;
  // do some things
  return 0;
}
4

5 回答 5

12

在 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 等)。但是虽然可以引用堆内存通过指针变量,指针变量本身的内存仅包含引用(内存地址),变量具有本地或静态/文件范围。

于 2013-06-07T09:16:02.010 回答
7

当它超出范围时,它将被释放。由于它具有函数作用域,这将在函数返回时发生。

于 2013-06-07T09:13:08.697 回答
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 宏非常有用。有时您想定义一个复杂的本地宏而不是一个函数以提高速度和整体简单性。在一个项目中,我想操作大型位图,但是使用函数来执行“和”“或”“异或”操作有点痛苦。位图的大小是固定的,所以我创建了一些宏:

#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 等没有问题,该块只执行一次(因为在块的 END 检查了 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 循环以及我可能需要的任何其他内容。

于 2013-06-07T09:33:44.467 回答
1

i在栈上分配。执行 return 时将其释放。

于 2013-06-07T09:13:29.697 回答
0

当变量超出范围时,变量i将被释放。在您的代码中,变量将在return 0语句执行后被释放。您可以在此处找到有关变量范围的更多信息

于 2013-06-07T09:16:41.360 回答