为什么编译器不会抱怨访问超出动态数组边界的元素?

时间:2011-07-21 09:01:21

标签: c++

我正在定义一个大小为9的数组。但是当我访问数组索引10时,它没有给出任何错误。

int main() {
   bool* isSeedPos = new bool[9];
   isSeedPos[10] = true;
}

我希望得到编译器错误,因为我的数组中没有数组元素isSeedPos[10]

为什么我没有收到错误?

13 个答案:

答案 0 :(得分:5)

这不是问题。

C ++数组中没有绑定检查。您可以访问超出数组限制的元素(但这通常会导致错误)。

如果你想使用一个数组,你必须自己检查你是不是在界外(你可以将sizee保存在一个单独的变量中,就像你所做的那样)。

当然,更好的解决方案是使用标准库容器,例如std::vector。 使用std::vector,您可以

  • 使用myVector.at(i)方法获取第i个元素(如果超出界限则会抛出异常)
  • 使用与{C风格数组相同的语法myVector[i],但您必须自己进行边界检查(例如在访问之前尝试if (i < myVector.size()) ...

另请注意,在您的情况下,std::vector<bool>是一个专门版本,因此每个bool只占用一位内存(因此它使用的内存少于bool数组,可能是也可能不是你想要的东西。

答案 1 :(得分:1)

不,编译器不需要为此情况发出诊断信息。编译器不会为您执行边界检查

您有责任确保不要编写这样的损坏代码,因为编译器不会错误

答案 2 :(得分:1)

与java和python等其他语言不同,数组访问不受C或C ++的绑定检查。这使得访问数组更快。您有责任确保自己保持在一定范围内。

但是,在这种简单的情况下,一些编译器可以在编译时检测错误。

此外,某些工具(如valgrind)可以帮助您在运行时检测此类错误。

答案 3 :(得分:1)

您使用的编译器/调试器是什么? MSVC ++会抱怨它并告诉你你写出了一个数组的界限。 但是标准并不要求这样做。 它可能随时崩溃,导致未定义的行为。

答案 4 :(得分:1)

原始数组不进行边界检查。如果你想要边界检查,你应该使用std :: vector。在数组结束后你正在访问无效的内存,纯粹是运气好了。

答案 5 :(得分:1)

使用std :: vector代替。一些实现将在调试模式下进行边界检查。

答案 6 :(得分:1)

没有规则声明在c中检查内存访问,简单明了。当你要求一个bool数组时,操作系统可能会更快地为你提供一个16位的32位数组,而不是9位数组。这意味着你甚至可能不会写作或阅读别人的空间。

C ++很快,而且速度快的原因之一就是因为很少检查你正在做什么,如果你要求一些内存,那么编程语言就会假设你知道你在做什么,如果操作系统没有抱怨,那么一切都会运行。

答案 7 :(得分:1)

您所提供的索引没有运行时检查,访问元素10不正确但可能。有两件事可能发生:

  • 如果你“不走运”,这不会崩溃,并会返回你阵列后面的一些数据。
  • 如果您“幸运”,则阵列之后的数据不会被您的程序分配,因此禁止访问所请求的地址。这将由操作系统检测到,并将产生“分段错误”。

答案 8 :(得分:0)

没有问题!您只是访问不应访问的内存。您可以在阵列之后访问内存。

答案 9 :(得分:0)

这不是Java。在C或C ++中没有边界检查;你可以写给那个索引真是太幸运了。

答案 10 :(得分:0)

isSeedPos不知道数组有多大。它只是指向内存中位置的指针。当您指向isSeepPos[10]时,行为未定义。机会迟早会导致段错误,但不要求崩溃,并且肯定没有标准的错误检查。

答案 11 :(得分:0)

写这个位置很危险。

但是编译器会让你这样做 - 实际上你正在写一个超过分配给该数组的内存的最后一个字节=不是一件好事。

C ++与许多其他语言不太相似 - 它假设您知道自己在做什么!

答案 12 :(得分:0)

C和C ++都允许您写入任意内存区域。这是因为它们最初源自(并且仍然用于)低级编程,您可能合法地想要写入内存映射外设或类似内容,并且因为当程序员已经知道值时省略边界检查更有效将在(例如,对于数组中的0到N的循环,他/她知道0和N在边界内,因此检查每个中间值是多余的)。

然而,事实上,现在你很少想这样做。如果你使用arr [i]语法,你基本上总是想写入在arr中声明的数组,而不是做任何其他事情。但如果你愿意,你还可以。

如果您执行写入任意内存(就像在这种情况下那样),它将成为您程序的一部分,并且它会在您不知情的情况下更改其他一些关键数据(现在,或者稍后当你对代码进行更改并忘记你正在做的事情时;或者它将写入未分配给程序的内存,操作系统将关闭它以防止出现更严重的问题。

如今:

  • 如果你犯了一个明显的错误,很多编译器会发现它
  • 有一些工具可以测试你的程序是否写入未分配的内存
  • 你可以而且应该使用std :: vector,这是你想要边界检查的99%的时间。 (检查您是否使用at()或[]来访问它)