我在一个c++程序中分配值,就像这样:

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    return 0;
}

程序输出3和4。这应该是不可能的。我使用g++ 4.3.3

下面是编译和运行命令

$ g++ -W -Wall errorRange.cpp -o errorRange
$ ./errorRange
3
4

只有当分配数组[3000]=3000时,它才会给我一个分割错误。

如果gcc不检查数组边界,我怎么能确定我的程序是正确的,因为它可能导致一些严重的问题以后?

我将上面的代码替换为

vector<int> vint(2);
vint[0] = 0;
vint[1] = 1;
vint[2] = 2;
vint[5] = 5;
cout << vint[2] << endl;
cout << vint[5] << endl;

这个也不会产生误差。


当前回答

当你用int array[2]初始化数组时,为2个整数分配空间;但是标识符数组只是指向该空间的开始。当你访问数组[3]和数组[4]时,如果数组足够长,编译器会简单地增加地址以指向这些值的位置;尝试访问像数组[42]这样的东西,而不首先初始化它,您将最终获得内存中该位置已经存在的任何值。

编辑:

关于指针/数组的更多信息:http://home.netcom.com/~tjensen/ptr/pointers.htm

其他回答

一个很好的方法,我经常看到,我已经使用实际上是注入一些NULL类型的元素(或一个创建的,像uint THIS_IS_INFINITY = 82862863263;)在数组的末尾。

然后在循环条件检查时,TYPE *pagesWords是某种指针数组:

int pagesWordsLength = sizeof(pagesWords) / sizeof(pagesWords[0]);

realloc (pagesWords, sizeof(pagesWords[0]) * (pagesWordsLength + 1);

pagesWords[pagesWordsLength] = MY_NULL;

for (uint i = 0; i < 1000; i++)
{
  if (pagesWords[i] == MY_NULL)
  {
    break;
  }
}

如果数组中填充了结构类型,则此解决方案不会生效。

当你用C语言写'array[index]'时,它会把它转换成机器指令。

翻译是这样的:

获取数组的地址 获取数组所包含对象类型的大小 '将类型大小乘以索引' '将结果添加到数组地址' '读取结果地址中的内容'

结果处理的内容可能是数组的一部分,也可能不是数组的一部分。为了换取机器指令的惊人速度,你失去了计算机为你检查事物的安全网。如果你一丝不苟,小心谨慎,这不是问题。如果你粗心大意或犯了错误,你就会被烧伤。有时它可能会生成导致异常的无效指令,有时则不会。

C或c++不会检查数组访问的边界。

您正在堆栈上分配数组。通过数组[3]索引数组等价于*(array + 3),其中array是指向&array[0]的指针。这将导致未定义的行为。

在C语言中捕捉这种情况的一种方法是使用静态检查器,例如splint。如果你运行:

splint +bounds array.c

on,

int main(void)
{
    int array[1];

    array[1] = 1;

    return 0;
}

然后你会得到警告:

数组.c:(在函数main中) array.c:5:9:可能超出范围 存储: 数组[1] 无法解决约束的: 要求0 >= 1 需要满足的先决条件: require maxSet(array @ array.c:5:9) >= 1 地址以外的地址 分配的缓冲区。

正如现在在问题中提到的,使用std::vector::at将解决问题,并在访问前进行绑定检查。

如果你需要一个位于堆栈上的常量大小数组作为你的第一个代码,请使用c++ 11新容器std::array;作为向量,有std::array::at函数。事实上,这个函数存在于所有有意义的标准容器中。E,其中操作符[]被定义为:(deque, map, unordered_map),除了std::bitset,其中它被称为std::bitset::test。

当然,您正在重写堆栈,但是程序非常简单,因此不会注意到这种影响。