2010-11-24 59 views
1
#include <iostream> 
using std::cout; 
using std::endl; 

int a[] = { 10, 20 }; 

int b[] = { 30, 40 }; 

int main(int argc, char ** argv) 
{ 
int * p = a; 

for (int i = 0; i < 4; i++) 
{ 
    cout << *(p + i) << endl; 
} 

return 0; 
} 

它为什么工作?MVSC中阵列的存储器分配++

+1

你不应该依赖这种行为。 – 2010-11-24 08:02:41

+0

你是否暗示,该程序不会崩溃? – 2010-11-24 08:02:43

+0

另请参阅:http://stackoverflow.com/questions/671703/array-index-out-of-bound-in-c和http://stackoverflow.com/questions/3658383/accessing-array-beyond-the-限制 – 2010-11-24 08:10:54

回答

4

这是一个典型的例子未定义的行为Undefined behaviour并不意味着崩溃 - 这意味着未定义的beaviour - 它可以工作,崩溃,不工作,不崩溃,以及几乎任何其他事情

0

它偶尔的作品。

您的代码暴露了未定义的行为,并且在未定义的行为中,它也有可能显然“工作”。

1

它会工作(有时),因为编译器(有时 - 很好,经常)将数组放在内存中彼此相邻。从指向第一个数组中第一个位置的指针开始,可以(有时)通过增加指针来遍历两个数组。

记忆以这种方式布置的事实根本不能保证,也不是任何'真实'的程序应该依赖的东西。

由于该标准没有指定编译器在这种情况下应如何表现,因此称为未定义行为(UB)。一些信息here

0

我的猜测是,你的输出是:

10 
20 
30 
40 

你的代码依赖于未定义行为:你的情况ab似乎是在内存中连续的,但就是不保证

当达到未定义行为限制时,任何事情都可能发生。我的意思是说:它可以“工作”,或者它可能会崩溃,或者它可以向古巴发射导弹。

2

C和C++不会在运行时检查您尝试访问的内存位置。您可以访问阵列之外的存储单元,这将会起作用。如果以这种方式访问​​你知道的内存(C++标准或你的编译器告诉你如何分配的内存),任何事情都可以正常工作(你甚至可以真正这样做),否则这是一个错误,你的应用程序将得到不可预知的行为。

就你而言,这意味着ab在连续的存储单元上。无论如何,这只取决于你的编译器。如果您使用其他编译选项,则您的代码可能无法在不同的编译器上,不同版本的编译器上或甚至在同一编译器上工作。

0

因为编译器在内存中分配b权利a。尝试打印每个循环迭代的实际地址abp,您会看到它很漂亮。这就是在连续行中声明的变量通常会发生的情况。 但是你不能相信这一点。编译器优化可以做其他事情。如果您需要确信分配给两个变量的内存是连续的,请使用struct

0

它的工作原理是因为你的编译器以ab的方式分配了内存,b紧跟在a之后。这是不可重现的,这就是为什么你有未定义的行为

只需在ab之间插入另一个变量,使用其他编译器或(我最喜欢的:)重命名变量。我见过一个按字母顺序排列变量的编译器。

您的代码意外“有效”。

0

这是一个未定义的行为,所以它通常不起作用。一个不好的例子是clang。这个编译器足够聪明,可以在启用链接时优化时优化b