8

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

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

2 * 1000然后分配了for ints + 4 * 1000for floats的内存?

4

5 回答 5

5

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

于 2013-09-02T04:47:04.720 回答
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()会编译。

那么它在内存中的什么位置呢?

i和的内存j仅保留在堆栈上。这与使用malloc(). 这很重要,因为相比之下调用malloc()非常慢。此外,使用动态分配的内存,malloc()您必须调用free().

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

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

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

运行时效率注意事项

在上面的示例中,我将值分配给iand j。这确实占用了少量的运行时间。j仅在评估 if 语句和随后的分支到 wherej被声明后才被赋值为 1。

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

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
}

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

当然,在这些琐碎的例子中,编译器会优化掉不必要的代码等。在实际代码中,编译器无法提前预测执行流程将是什么,那么事情就会留在原地。

于 2013-09-02T05:23:37.233 回答
1

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

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

请记住,这是由于语言的语义而发生的。块结构引入了一个新的作用域,并且在该作用域中分配的任何自动变量都具有与作用域一样长的生命周期。在 C 中,这是通过将其分配到堆栈上来实现的,堆栈会随着作用域的消失而崩溃。

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

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

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

于 2013-09-02T05:06:38.490 回答
0

块中数组的内存if将在运行时在堆栈上分配。else部分将由编译器优化(删除)。有关变量将在何处分配内存的更多信息,请参阅写入字符串时的分段错误

于 2013-09-02T04:56:25.810 回答
0

正如DCoderpaddy纠正我的那样,内存将在编译时计算,但在运行时在堆栈内存段中分配,但具有定义数组的块的范围和生命周期。分配的内存大小取决于系统中int&float的大小。阅读本文以了解 C 内存映射的概述

于 2013-09-02T04:47:43.403 回答