我在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;
}
Run Code Online (Sandbox Code Playgroud)
程序打印3和4.应该是不可能的.我正在使用g ++ 4.3.3
这是编译和运行命令
$ g++ -W -Wall errorRange.cpp -o errorRange
$ ./errorRange
3
4
Run Code Online (Sandbox Code Playgroud)
只有在分配时才array[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;
Run Code Online (Sandbox Code Playgroud)
而且这个也没有产生任何错误.
jal*_*alf 327
欢迎来到每个C/C++程序员最好的朋友:Undefined Behavior.
由于各种原因,语言标准没有指定很多内容.这是其中之一.
通常,每当遇到未定义的行为时,都可能发生任何事情.应用程序可能会崩溃,它可能会冻结,它可能会弹出你的CD-ROM驱动器或让恶魔从你的鼻子里出来.它可能会格式化您的硬盘或将所有色情内容通过电子邮件发送给您的祖母.
它甚至可以,如果你真的不走运,似乎才能正常工作.
该语言简单地说明了如果访问数组边界内的元素会发生什么.如果你走出界限会发生什么事情.它现在似乎可以在您的编译器上运行,但它不是合法的C或C++,并且无法保证它在下次运行程序时仍然可用.或者说,它不会被覆盖的基本数据即使是现在,你只是还没有遇到的问题,它是会导致-但.
至于为什么没有边界检查,答案有几个方面:
std::vector类模板,允许两者.operator[]旨在提高效率.语言标准不要求它执行边界检查(尽管它也不禁止它).向量还具有保证执行边界检查的at()成员函数.因此,在C++中,如果使用向量,则可以获得两全其美的效果.您可以在没有边界检查的情况下获得类似数组的性能,并且您可以在需要时使用边界检查访问.Ric*_*den 28
使用g ++,您可以添加命令行选项: -fstack-protector-all.
在您的示例中,它产生以下结果:
> g++ -o t -fstack-protector-all t.cc
> ./t
3
4
/bin/bash: line 1: 15450 Segmentation fault ./t
Run Code Online (Sandbox Code Playgroud)
它并没有真正帮助你找到或者解决问题,但至少段错误会让你知道什么是错的.
Ark*_*nez 12
g ++没有检查数组边界,你可能用3,4覆盖了一些东西,但没有什么真正重要的,如果你尝试使用更高的数字,你就会崩溃.
您只是覆盖了未使用的堆栈部分,您可以继续直到到达堆栈的已分配空间的末尾并最终崩溃
编辑:你无法解决这个问题,也许静态代码分析器可能会揭示这些故障,但这太简单了,即使对于静态分析器,也可能有类似(但更复杂)的故障未被发现
据我所知,这是未定义的行为.使用它运行一个更大的程序,它将在整个过程中的某个地方崩溃.边界检查不是原始数组(甚至是std :: vector)的一部分.
使用std :: vector std::vector::iterator代替,所以你不必担心它.
编辑:
只是为了好玩,运行它,看看你崩溃多久:
int main()
{
int array[1];
for (int i = 0; i != 100000; i++)
{
array[i] = i;
}
return 0; //will be lucky to ever reach this
}
Run Code Online (Sandbox Code Playgroud)
EDIT2:
不要跑那个.
EDIT3:
好的,这是关于数组及其与指针的关系的快速课程:
当您使用数组索引时,您实际上正在使用伪装的指针(称为"引用"),该指针会自动解除引用.这就是为什么而不是*(array [1]),array [1]会自动返回该值的值.
当你有一个指向数组的指针时,如下所示:
int array[5];
int *ptr = array;
Run Code Online (Sandbox Code Playgroud)
然后第二个声明中的"数组"实际上已经衰减为指向第一个数组的指针.这与此相同:
int *ptr = &array[0];
Run Code Online (Sandbox Code Playgroud)
当你尝试访问超出你分配的内容时,你实际上只是使用指向其他内存的指针(C++不会抱怨).以上面的示例程序,这相当于:
int main()
{
int array[1];
int *ptr = array;
for (int i = 0; i != 100000; i++, ptr++)
{
*ptr++ = i;
}
return 0; //will be lucky to ever reach this
}
Run Code Online (Sandbox Code Playgroud)
编译器不会抱怨,因为在编程中,您经常需要与其他程序进行通信,尤其是操作系统.这是用指针完成的.
运行这个通过Valgrind命令,您可能会看到错误。
正如 Falaina 指出的那样,valgrind 没有检测到许多堆栈损坏的实例。我刚刚在 valgrind 下尝试了示例,它确实报告了零错误。然而,Valgrind 可以帮助发现许多其他类型的内存问题,在这种情况下它并不是特别有用,除非你修改你的 bulid 以包含 --stack-check 选项。如果您构建并运行示例
g++ --stack-check -W -Wall errorRange.cpp -o errorRange
valgrind ./errorRange
Run Code Online (Sandbox Code Playgroud)
valgrind会报错。
如果你想有快速约束大小的数组与范围错误检查,请尝试使用升压::数组(也性病:: TR1 ::阵列由<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;
}
Run Code Online (Sandbox Code Playgroud)
该程序将打印:
array.at(0) = 1
Something goes wrong: array<>: index out of range
Run Code Online (Sandbox Code Playgroud)