什么时候在c中释放内存?

时间:2013-06-07 09:12:17

标签: c memory-management

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

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

5 个答案:

答案 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

上找到更多信息