我在一个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;

这个也不会产生误差。


当前回答

欢迎来到每一个C/ c++程序员最好的朋友:未定义行为。

由于各种原因,语言标准中没有指定很多内容。这是其中之一。

一般来说,无论何时遇到未定义的行为,都可能发生任何事情。应用程序可能会崩溃,可能会冻结,可能会弹出您的CD-ROM驱动器,或者让恶魔从您的鼻子里出来。它可能会格式化你的硬盘,或者把你所有的色情片都发给你的祖母。

如果你真的很不幸,它甚至可能看起来工作正常。

该语言只是说明如果访问数组范围内的元素应该发生什么。它没有定义如果你出界会发生什么。它今天在编译器上似乎可以工作,但它不是合法的C或c++,并且不能保证它在下次运行程序时仍然可以工作。或者它现在还没有覆盖基本数据,您还没有遇到它将导致的问题。

至于为什么没有边界检查,有几个方面的答案:

An array is a leftover from C. C arrays are about as primitive as you can get. Just a sequence of elements with contiguous addresses. There is no bounds checking because it is simply exposing raw memory. Implementing a robust bounds-checking mechanism would have been almost impossible in C. In C++, bounds-checking is possible on class types. But an array is still the plain old C-compatible one. It is not a class. Further, C++ is also built on another rule which makes bounds-checking non-ideal. The C++ guiding principle is "you don't pay for what you don't use". If your code is correct, you don't need bounds-checking, and you shouldn't be forced to pay for the overhead of runtime bounds-checking. So C++ offers the std::vector class template, which allows both. operator[] is designed to be efficient. The language standard does not require that it performs bounds checking (although it does not forbid it either). A vector also has the at() member function which is guaranteed to perform bounds-checking. So in C++, you get the best of both worlds if you use a vector. You get array-like performance without bounds-checking, and you get the ability to use bounds-checked access when you want it.

其他回答

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

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

在Valgrind中运行这个,你可能会看到一个错误。

正如Falaina指出的那样,valgrind并没有检测到很多堆栈损坏的实例。我刚刚在valgrind下尝试了样本,它确实报告了零错误。然而,Valgrind可以帮助发现许多其他类型的内存问题,在这种情况下,它不是特别有用,除非你修改你的构建,包括——stack-check选项。如果构建并运行样例为

g++ --stack-check -W -Wall errorRange.cpp -o errorRange
valgrind ./errorRange

Valgrind将报告一个错误。

当你声明int数组[2];您保留了2个内存空间,每个空间4个字节(32位程序)。 如果你在代码中输入数组[4],它仍然对应一个有效的调用,但只有在运行时它才会抛出一个未处理的异常。c++使用手动内存管理。这实际上是一个用于黑客程序的安全漏洞

这有助于理解:

某个指针;

somepointer [0] = somepointer [5];

libstdc++是gcc的一部分,它有一个用于错误检查的特殊调试模式。它由编译器标志-D_GLIBCXX_DEBUG启用。其中,它以性能为代价对std::vector进行边界检查。这是gcc最新版本的在线演示。

因此,实际上您可以使用libstdc++调试模式进行边界检查,但您应该只在测试时执行,因为与正常的libstdc++模式相比,它的性能损失显著。

The behavior can depend on your system. Typically, you will have a margin for out of bounds, sometimes with value of 0 or garbage values. For the details you can check with memory allocation mechanism used in your OS. On top of that, if you use the programming language like c/c++, it will not check the bounds when you using some containers, like array. So, you will meet "undefined event" because you do not know what the OS did below the surface. But like the programming language Java, it will check the bound. If you step outside of the bound, you will get an exception.