7

为什么我编译时没有给出错误?

#include <iostream>
using namespace std;

int main()
{
    int *a = new int[2];
    // int a[2]; // even this is not giving error
    a[0] = 0;
    a[1] = 1;
    a[2] = 2;
    a[3] = 3;
    a[100] = 4;
    int b;

    return 0;
}

有人可以解释为什么会这样。提前致谢。)

4

4 回答 4

12

因为未定义的行为 == 任何事情都可能发生。你很不幸它没有崩溃,这种行为可能会隐藏错误。

至于a被定义两次 - 这是编译器中的一个错误。

于 2012-09-13T15:43:04.533 回答
10

声明两个被调用的变量a肯定是错误的;如果你的编译器接受了,那么它就坏了。我假设您的意思是,如果您将一个声明替换为另一个声明,您仍然不会收到错误消息。

数组访问没有范围检查。在编译时,数组的大小通常是未知的,即使知道,语言也不需要检查。在运行时,检查会降低性能,这违背了不为不需要的东西付费的 C++ 理念。因此,超出数组末尾的访问会产生未定义的行为,程序员需要确保它不会发生。

有时,无效访问会导致分段错误,但这并不能保证。通常,内存保护仅适用于整个内存页面,典型的页面大小为几千字节。有效内存页面内的任何访问都不会被捕获。您访问的内存很有可能包含一些其他程序变量或调用堆栈的一部分,因此在那里写入可能会以您可以想象的任何方式影响程序的行为。

如果你想安全,你可以使用, 并且只能使用它的函数std::vector访问它的元素。at()这将检查索引,如果超出范围则抛出异常。它还将为您管理内存分配,修复示例中的内存泄漏。

于 2012-09-13T15:53:46.533 回答
5

我猜你来自 Java 或类似 Java 的语言,一旦你走出数组的边界,就会得到“数组索引越界”异常。

好吧,C 对你有更多的期望;它节省了您要求的空间,但它不会检查您是否超出了所节省空间的边界。一旦你按照上面提到的那样做,程序就会出现可怕的未定义行为。

请记住,如果您的程序中存在错误并且您似乎无法找到它,并且当您检查代码/调试它时,一切似乎都很好,那么您很有可能会“出局” bounds”并访问一个未分配的地方。

于 2012-09-13T16:45:11.320 回答
0

具有良好代码分析的编译器肯定会警告该代码引用超出您的数组分配。忘记多个 a 声明,如果您运行它,它可能会或可能不会出错(正如其他人所说的未定义行为)。例如,如果你有一个 4KB 的堆页面(在处理器地址空间中),如果你不在那个页面之外写,你就不会从处理器那里得到错误。删除数组后,如果您已经删除了,并且根据堆实现,堆可能会检测到它已损坏。

于 2012-09-13T17:26:24.673 回答