案例1:
int main()
{
int T=5;
while(T--){
int a;
cout<<&a<<"\n";
}
}
它打印相同的地址5次。
我想它应该打印5个不同的地址。
案例2:
int main()
{
int T=5;
while(T--){
int* a=new int;
cout<<a<<"\n";
}
}
打印5个不同的地址
我的问题是:
为什么每次在第一种情况下遇到变量声明时都没有分配新内存?
以及第一案和第二案的区别。
答案 0 :(得分:3)
在第一种情况下,a
位于堆栈上。基本上,a
在每次迭代中得到“构造”(更好的措辞可能是“分配的空间”)并在之后释放。因此,在每次迭代之后,先前分配给a
的空间再次空闲,新的a
在下一次迭代中获得该空间。这就是地址相同的原因。
在第二种情况下,您在堆上分配内存,并且(另外)不要再次释放它。因此,在下一次迭代中无法重新分配内存。
答案 1 :(得分:1)
理论上,每次变量进入范围时都会分配堆栈上的绝对位置,并在每次超出范围时解除分配。然后,分配它的堆栈的LIFO特性确保每次分配相同的位置。
但实际上,编译器在编译时会在堆栈上分配相对位置,只要这样做是可行的(在这种情况下通常是真的)。通过预先分配的相对位置,进入函数的简单行为有效地分配了所有局部变量的所有实例。类似循环中的本地对象将为每个实例构造和/或初始化,但是对于所有实例预先进行一次分配。因此,地址是相同的,其原因甚至比堆栈的LIFO特性更为根本。它们是相同的,因为分配只进行了一次。
如果您的C ++编译器支持常见的C99功能,您可以构建可能区分上述两种情况的测试。大致像:
for (int i=0; i<2; ++i) {
int unpredictable[ f(i) ];
for (int j=0; j<2; ++j) {
int T=5;
// does the location of T vary as i changes ??
int U[ f(j) ]; // I'm pretty sure the location of U varies
}}
我们希望f(0)和f(1)的值在运行时很容易,但优化器在编译时很难看到。如果f在此模块中声明但在另一个模块中定义,那么这是最强大的。
通过阻止编译器在编译时完成所有分配,可能我们阻止它在编译时进行一些简单的分配,或者它仍然可以排除那些可以在编译时分配的分配时间和运行时分配仅在需要时使用。
答案 2 :(得分:0)
这取决于编译器。由于变量是在最里面的范围内声明的,因此编译器认为可以为变量重用相同的位置。当然它可以位于不同的地址。