访问未分配的内存C ++

时间:2015-01-10 20:51:42

标签: c++ arrays pointers memory

我正在使用这段代码:

try
{
    int* myTestArray = new int[2];

    myTestArray[4] = 54;

    cout << "Should throw ex "  << myTestArray[4] + 1 << endl;
}
catch (exception& exception)
{ 
    cout << "Exception content: " << exception.what() << endl;
}

对我来说真正的好处是,为什么不抛出异常,因为它被访问了一个未分配的索引......以及为什么要打印55? C ++会自动增加数组的大小吗?

6 个答案:

答案 0 :(得分:10)

这里有一个未说明的,不正确的假设。这个假设是C ++实际上对你用内存做了什么感到很遗憾。 C ++与它的C祖先一样,具有完全未经检查的内存模型。你在这里经常被称为缓冲区溢出,并且是无数错误的来源,包括一些可怕的安全漏洞。

以下是您的代码所说的内容:

  • myTestArray是内存中某个位置的名称,其大小足以容纳int的地址。

  • 已经在堆上为它分配了两个int的内存。 [并且addreress被放入位置myTestArray。没关系,但这可能会让它更清晰。] (可能还有16个字节的开销,但我们现在不关心。)

  • 然后您将值54保留在int中包含的地址的myTestArray内存位置。

  • 查看该位置,添加1并打印结果。

你证明C(++)确实不在乎。

现在,在大多数情况下,底层内存管理和运行时系统都不会让你逃脱它;你将违反它的假设并得到分段错误或类似的东西。但是在这种情况下,你还没有达到边界,很可能是因为你正在调整malloc正在使用的数据结构来管理堆。你正在逃避它,因为程序其余部分的堆没有发生任何事情。但是为了一个真正的美好时光,编写一个执行此代码的小循环,释放myTestArray并重新分配它。在程序爆炸之前我不会超过10次迭代,而且可能不会生成两次。

答案 1 :(得分:9)

无法保证访问未分配的内存会引发异常。

实际上并不能保证做任何事情,因为这是未定义的行为。什么事情都可能发生。小心鼻子恶魔。

它打印55因为你刚存储54,取回它然后打印54 + 1。它根本不能保证打印55,尽管这通常会在实践中发生。这次它奏效了。

答案 2 :(得分:1)

你可以写出数组范围,但不能保证工作,并且不保证数据在那里是持久的,因为其他东西可以覆盖它。

这不是一个好主意,因为没有例外,可能很难找到错误。

当读取那个内存时,你会从其他一些程序或以前使用过的内存中留下一些随机垃圾,所以它真的可以是任何东西。

答案 3 :(得分:1)

正如其他人所说,这是未定义的行为,但我认为更多的信息可能有所帮助。 myTestArray在类型意义上不是“数组”,具有特殊运算符等。它只是指向内存中某个位置的指针。表达式myTestArray[4]只是*(myTestArray+4)的简写 - 它返回对4 * sizeof(int)过去myTestArray的内存位置的引用。如果您想要边界检查,则必须使用std::vector<int>::at()

答案 4 :(得分:1)

知道这里发生了什么肯定很难做到。但我可以给你一个粗略的想法。

大多数操作系统都具有内存分配的最小大小。在Unix中,它是本机页面大小。在x86和amd64系统上,这是4 kB。在Windows中它是64 kB(我认为)。

mallocnew使用的内存分配器从此大小的块中获取操作系统的内存。它设置数据结构(通常是链表,有时是位图或树),并分发所需大小的小块。

另一个令人困惑的事情是,在程序开始运行main()之前,它已经运行了相当多的其他代码并分配了内存。对于std::cout和其他静态和全局对象,以及共享库链接。

但是假设当你调用new时,你的程序首先得到一个4 kB的块,并给你一个指向它的8个字节的指针(两个整数)。你的程序分配了整个4 kB,你可以在那里写入而不会崩溃。但是,如果再次致电new会怎样?内存分配器很可能在某个地方写入了一些重要的跟踪信息到4 kB。下一个字节可能是以下块的大小。将54写入其中可能会使其认为它具有比它更多或更少的内存。或者那些字节可能是指向下一个可用内存块的指针,而你的54将导致下一次内存分配使程序崩溃。

答案 5 :(得分:0)

访问数组超出范围是未定义的行为。因此,55是许多可能的结果之一,这里没有什么令人惊讶的。

C ++标准版n3337 § 5.7添加运算符

  

5)当添加或减去具有整数类型的表达式时   从指针开始,结果具有指针操作数的类型。如果   指针操作数指向数组对象的元素和数组   足够大,结果指向一个偏离的元素   原始元素使得下标的差异   结果和原始数组元素等于整数表达式。   换句话说,如果表达式P指向一个的第i个元素   数组对象,表达式(P)+ N(等效地,N +(P))和(P)-N   (其中N的值为n)分别指向i + n和i -   数组对象的第n个元素,只要它们存在即可。而且,如果   表达式P指向数组对象的最后一个元素,即   表达式(P)+1指向数组对象的最后一个元素,   如果表达式Q指向一个数组的最后一个元素   对象,表达式(Q)-1指向数组的最后一个元素   宾语。如果指针操作数和结果都指向元素   相同的数组对象,或一个超过数组的最后一个元素   对象,评估不得产生溢出; 否则,   行为未定义