堆和栈的区别

4
请告诉我关于以下代码,堆栈与堆的区别是什么?
int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
    arr [3000] = 8 ; //SIGSEGV 

    a = malloc (sizeof (int));
    a[4] = 6; 
    a[4000] = 8; //No error
}

我知道arr是一个静态数组,当我执行arr[3000]时,我正在访问其他进程的地址,这会导致SIGSEGV错误。但是我不明白为什么a[4000]不会给我任何运行时错误,即SIGSEGV信号。

谢谢

6个回答

9

不能保证任何这些调用是否实际写入了无法访问的内存(这将触发段错误)。同样有可能程序具有向该内存写入的权限而不会触发段错误,但会覆盖与您的数组无关的其他内部数据。当然,这可能导致程序其他地方出现意外效果。

通常被称为未定义行为。在数组越界时没有做出任何承诺,任何事情都可能发生或可能不发生。


2
而且,更糟糕的是,意外的影响可能意味着未检测到的数据损坏。 - ninjalj
@sth,感谢您澄清我的疑问。也感谢所有回复的人。 - Nikhil

3

引用数组界外的元素是未定义的行为,这意味着可能发生任何事情(异常、无异常或其他)。arr[5]赋值没有引起错误的原因可能是该值仍在有效的堆栈空间内(但在运行时间更长的应用程序中可能会导致错误)。对分配的数组进行无效赋值可能导致对进程的存储器页面进行写操作,因此不会引起错误。但是这种情况可能因运行而异。即使地址属于进程地址空间之外的页面,实际发生的情况也取决于操作系统。


1
其中,长一点可能被定义为仅从该函数返回。 - ninjalj
@mark 那么当对已分配的数组进行无效赋值时,也会导致分段错误吗? - Nikhil
@NikhilTej:是的,这当然是可能的。 - Mark Wilkins
@NikhilTej:从技术上讲,当你很幸运的时候,你能够检测到错误。不幸的是,如果直到在生产环境中数据被破坏之前才发现错误,那就意味着你很不幸。 - ninjalj

1

堆是你使用malloc()在内存中申请的内存块所在的区域。

a[4000] = 8; 并没有失败,因为它恰好没有落入其他进程的内存地址中。这只是偶然发生的。


1
所有你指出的情况都代表了“未定义行为”。
在一些情况下,它是一个 noop,而在另一些情况下,它是段错误。
特别糟糕的是,“未定义行为”可能在一段时间内按预期工作,但突然开始产生“不良副作用”(即段错误)。这使得在生产中调试和重现这些条件非常困难。

1

缓冲区溢出是未定义的行为。如果缓冲区溢出在堆栈上,则可能在星期一崩溃;如果在堆上,则可能在星期二崩溃。它们只是未定义的行为。

这里是C段落,说明它是未定义的行为:

(C99, 6.5.6p8) "如果结果指向数组对象的最后一个元素之一,则不得将其用作评估的一元*运算符的操作数。"

当然,[]是一个伪装的一元*运算符:

(6.5.2.1p2) "下标运算符[]的定义是E1[E2]等同于(*((E1)+(E2)))。"


1
int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
// J: False - it is undefined. expect raptors, or something.

    arr [3000] = 8 ; //SEGSEV
// J: Now you see the effects of undefined behavior, even though you did not in a previous invalid access.

    a = malloc (sizeof (int));
    a[4] = 6; // J: Still undefined behavior
    a[4000] = 8; //No error
// J: Still undefined behavior
}

但我不明白为什么a[4000]不会给我任何运行时错误,即segsev信号。
在另一个平台或架构上会出现这种情况。这真的无关紧要 - 你必须始终避免UB。
无论如何,差异在于您系统的分配器的实现(假设编译器没有将malloc的结果放置在堆栈上)。
您的分配器如何管理和分配内存是您不应该依赖的实现细节,特别是当您在周围抛出UB时。
分配器可以从较大的物理分配中提供内存块。这种底层实现因平台而异。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接