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

这个也不会产生误差。


当前回答

Hint

如果你想要快速约束大小数组的范围错误检查,尝试使用boost::array,(也std::tr1::array from <tr1/array>,它将是下一个c++规范的标准容器)。它比std::vector快得多。它在堆上或类实例内部保留内存,就像int array[]一样。 这是一个简单的示例代码:

#include <iostream>
#include <boost/array.hpp>
int main()
{
    boost::array<int,2> array;
    array.at(0) = 1; // checking index is inside range
    array[1] = 2;    // no error check, as fast as int array[2];
    try
    {
       // index is inside range
       std::cout << "array.at(0) = " << array.at(0) << std::endl;

       // index is outside range, throwing exception
       std::cout << "array.at(2) = " << array.at(2) << std::endl; 

       // never comes here
       std::cout << "array.at(1) = " << array.at(1) << std::endl;  
    }
    catch(const std::out_of_range& r)
    {
        std::cout << "Something goes wrong: " << r.what() << std::endl;
    }
    return 0;
}

这个程序将打印:

array.at(0) = 1
Something goes wrong: array<>: index out of range

其他回答

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

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

欢迎来到每一个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.

g++不检查数组边界,你可能会用3,4覆盖一些东西,但这没什么大不了的,如果你尝试用更大的数字,你会崩溃。

你只是覆盖了堆栈中没有使用的部分,你可以继续,直到你到达为堆栈分配的空间的尽头,它最终会崩溃

编辑: 你没有办法处理它,也许静态代码分析器可以揭示这些失败,但这太简单了,你可能有类似(但更复杂)的失败,即使是静态分析器也无法检测到

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

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

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

Valgrind将报告一个错误。

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

编辑:

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