如果索引超过数组末尾,为什么我需要指定数组长度?

时间:2015-01-24 01:11:47

标签: c++ arrays undefined-behavior

定义一个包含2个元素的数组

char a[2];

然后分配值并打印第4个元素。

a[0]='a';
a[1]='b';
a[2]='c';
a[3]='d';
cout<<a[3]<<endl;

为什么我能得到答案'd'而不是运行时错误?在声明数组a时,值[2]代表[]内部的值是什么?如果2在这里没有意义,为什么我不能把它写成:

char a[];

1 个答案:

答案 0 :(得分:2)

C和C ++中的索引操作符a[b]可以视为定义为*(&a + sizeof(TA) * b),(有趣的是,a[b]b[a]也是等效的,但那是另一种解释。)

让我们来看看代码:

char a[2]; // statically-allocates 2 bytes on the stack, e.g. at `0xFFFF`, and `0xFFFE` (as the stack grows downwards)
a[0] = 'a'; // sets `0xFFFF`
a[1] = 'b'; // sets `0xFFFE`
a[2] = 'c'; // sets `0xFFFD` <-- danger!

这就存在危险:C / C ++没有强制要求数组代码进行边界检查,因此您的代码可以被认为与此等效:

char a0; // 0xFFFF
char a1; // 0xFFFE
*0xFFFF = 'a';
*0xFFFE = 'b';
*0xFFFD = 'c'; <-- danger! writing to unallocated memory
*0xFFFC = 'd'; <-- uncharted territory! here be dragons!

您的代码&#34;工作&#34;因为0xFFFD将是存在的内存有两个原因:1:堆栈向下增长并由操作系统自动保留,因此您不会遇到段错误(&#34;访问冲突&#34;在Windows上) ,2:你没有接近堆栈溢出错误状态。

但是,如果要向函数添加更多局部变量,那么您将看到a[2]将覆盖这些值,您还可能会覆盖当前堆栈帧的返回地址从而破坏你的堆栈并使你的程序处于一个应该立即终止的不确定状态。)

考虑:

char[2] a;
int     b = 0;
int     c = 0;

a[2] = 'a';

assert( b == 0 ); // this assertion will fail (at least on systems that don't word-align locals)