C++静态声明和动态声明在内部有什么区别?

3

I have two codes:
Normal:

int* p[5];
for (int i=0;i<5;i++){
    int s = rand()%25;
    p[i]=&s;
}

动态:

int* p[5];
for (int i=0;i<5;i++){
    int* s = new int;
    *s = rand()%25; //Edit: typo, I didn't want to make a random pointer
    p[i]=s;
}

现在,如果我打印数组 p,先打印 p[i],然后再打印*p[i],我会得到如下结果:
 static             dynamic
0x22ff04 7         0x22ff30 7
0x22ff04 7         0x22ff24 14
0x22ff04 7         0x22ffa6 2
0x22ff04 7         0x22ff89 8
0x22ff04 7         0x22ff13 21

为什么在普通声明中,所有元素都指向同一位置,而在动态声明中会创建多个对象?
这是为什么呢?


3
你是将一个指针随机赋值吗?s = rand()%25; 然后又取一个临时变量的地址吗? o.O 总之:UB(未定义行为)。 - Bartek Banachewicz
是的,抱歉,我忘记在代码最后一次更改后添加星号了。对不起。 - SmRndGuy
3个回答

6
在第一种情况下,所有的条目都指向 s 并在 s 超出作用域时留下了悬空。 解引用p [i]会导致未定义的行为。
在第二种情况下,每个条目都指向一个单独的堆分配对象。 在这里,没有未定义的行为(但存在内存泄漏)。

在第二种情况下,他们实际上是在写入动态分配对象的指针。编辑:不再是这样。 - Joseph Mansfield
@sftrabbit:我认为这是问题中的一个打字错误,现在已经被修正了。 - NPE

4
我有一种隐约的感觉,你想要一个随机值的数组:
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iterator>

int main()
{
    std::srand(time(0)); // Don't forget to seed!

    std::vector<int> v(5);
    std::generate(v.begin(), v.end(), random);

    // or
    std::vector<int> w;
    std::generate_n(std::back_inserter(w), 5, random);
}

1
在第一种情况下,每次迭代时你在堆栈上分配一个整数,然后将该地址分配给数组。由于堆栈上没有其他变量,因此s总是分配在相同的堆栈地址上,最终导致p的所有元素指向包含最后一个随机值(即7)的相同地址。此外,在退出循环后,你不知道可以在此地址上写入什么,因为在离开s作用域后,编译器可以使用相同的地址来存储其他数据。你可以通过将int s移到循环外部来防止这种情况发生,但仍然会使p的所有元素指向相同的堆栈地址。
在第二种情况下,每次迭代时你在堆上分配一个新的整数,因此p指向5个不同的对象/地址。
你想要实现什么?

“总是分配在相同地址上”的做法不能保证。栈地址包含任何值都是不能保证的 - 在循环内获取的地址的任何使用都是未定义行为。当然,将s移出循环会改变一切。 - Arne Mertz
当然不能保证。这取决于编译器认为最合适的方式。 - Zdeslav Vojkovic
只是想强调一下,他在第一个循环中所做的完全是未定义行为,并且比仅产生令人困惑的结果更具有惩罚性 ;) - Arne Mertz
我完全同意。你真的希望这段代码崩溃,而不是悄悄地交付给客户。 - Zdeslav Vojkovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接