如果我在if语句中定义一个数组,那么内存是否被分配?

时间:2013-09-02 04:44:36

标签: c arrays memory

如果我在if语句中定义一个数组,那么在编译期间会分配内存,例如。

if(1)
{
    int a[1000];
} 
else
{
    float b[1000];
}

然后为浮点数的2 * 1000内存+ 4 * 1000的内存被分配?

5 个答案:

答案 0 :(得分:5)

它在运行时保留在堆栈上(假设一个非平凡的条件 - 在您的情况下,编译器将只排除else部分)。这意味着它只存在于范围块内({})之间。

答案 1 :(得分:1)

在您的示例中,只有int的内存在堆栈上分配(1000 * sizeof(int))。

你可以猜到,这是在运行时发生的。生成的代码具有在输入相应的代码块时在堆栈上分配空间的指令。

请记住,由于语言的语义,这种情况正在发生。块结构引入了一个新的作用域,在该作用域中分配的任何自动变量的生命周期都与作用域一样长。在C中,这是通过在堆栈上分配它来实现的,当范围消失时它会崩溃。

只是为了推动这一点,请注意,如果变量具有不同的性质,则分配会有所不同。

if(1)
 {
  static int a[1000];
 } 
else
 {
  static float b[1000];
 }

在这种情况下,为int和浮点分配空间。这些变量的生命周期是程序。但是可见性在它们被分配的块范围内。

答案 2 :(得分:1)

范围

在一对{ }范围内声明的变量在堆栈中。这适用于在函数开头或函数内的任何{ }对中声明的变量。

int myfunc()
{
   int i = 0;   // On the stack, scoped: myfunc

   printf("%i\n");

   if (1)
   {
       int j = 1;   // On the stack, scope: this if statement

       printf("%i %i\n",i,j);
   }

   printf("%i %i\n",i,j);   // Won't work, no j
}

目前,变量的范围仅限于周围的{ }。我记得一些较旧的Microsoft编译器没有限制范围,并且在上面的示例中,最终printf()将编译。

那么它在记忆中的位置是什么?

ij的内存仅保留在堆栈中。这与使用malloc()完成的内存分配不同。这很重要,因为相比之下调用malloc()非常慢。此外,使用malloc()动态分配内存时,您必须调用free()

实际上,编译器提前知道函数变量需要什么空间,并且将生成相对于调用myfunc()时堆栈指针所指向的内存的代码。只要堆栈足够大(通常为2MB,取决于操作系统),一切都很好。

在调用myfunc()且堆栈指针已经接近堆栈末尾的情况下发生堆栈溢出(即myfunc()由一个函数调用,而函数又由另一个函数调用它自己被另一个调用,等等。每一层嵌套的函数调用都会将堆栈指针移动一点,并且只有在函数返回时才会移回)。

如果堆栈指针和堆栈末尾之间的空间不足以容纳myfunc()中声明的所有变量,myfunc()的代码将只是尝试使用位置超出堆栈的末尾。这几乎总是一件坏事,而且注意到出现问题的确切程度有多糟糕和难度取决于操作系统。在小型嵌入式微控制器上,它可能是一场噩梦,因为它通常意味着程序数据的其他部分(例如全局变量)被静默覆盖,并且调试起来非常困难。在更大的系统(Linux,Windows)上,操作系统会告诉你发生了什么,或者只会使堆栈更大。

运行时效率注意事项

在上面的示例中,我将值分配给ij。这实际上占用了少量的运行时。只有在将if语句和后续分支评估到声明j的位置后,才会为j分配1。

比如说if语句没有被评估为true;在这种情况下j永远不会被分配1.如果在j的开头声明了myfunc(),那么无论if语句是否为真,它总是被赋值为1 - a很少浪费时间。但是考虑一个不太重要的例子,其中一个大数组被声明为初始化;这需要更多的执行时间。

int myfunc()
{
   int i = 0;           // On the stack, scoped: myfunc
   int k[10000] = {0}   // On the stack, scoped: myfunc. A complete waste of time
                        //  when  the if statement evaluates to false.

   printf("%i\n");

   if (0)
   {
       int j = 1;   // On the stack, scope: this if statement

       // It would be better to move the declaration of k to here
       // so that it is initialised only when the if evaluates to true.

       printf("%i %i %i\n",i,j,k[500]);

   }

   printf("%i %i\n",i,j);   // Won't work, no j
}

k的声明放在myfunc()的顶部意味着每次调用myfunc()时都会执行一个循环10,000长的初始化k。但它永远不会被使用,因此循环完全是浪费时间。

当然,在这些简单的例子中,编译器会优化不必要的代码等。在实际代码中,编译器无法提前预测执行流程将会是什么,然后事情就会存在。

答案 3 :(得分:0)

作为 DCoder & paddy 纠正了我,内存将在编译时计算,但在运行时分配在堆栈内存段中,但是使用范围&定义数组的块的生命周期。分配的内存大小取决于int&的大小。您系统中的float。阅读this for an overview on C memory map

答案 4 :(得分:0)

if块中数组的内存将在运行时在堆栈上分配。 else部分将由编译器优化(删除)。有关变量将在何处分配内存的更多信息,请参阅Segmentation Fault when writing to a string