如果我在使用calloc分配的内存之外设置一个值会发生什么?

问题描述 投票:1回答:5

考虑以下:

int* x = calloc(3,sizeof(int));
x[3] = 100;

它位于一个函数内部。

编译和运行程序时没有错误,但是当我用valgrind运行它时,我得到一个“4号无效写入”。

我知道我在使用calloc分配的内容之外访问内存,但我正在尝试了解实际发生的情况。

堆栈中的某些地址(?)是否仍然具有值100?因为必须有比我用calloc分配的内存更多的可用内存。 valgrind错误更像是“嘿,你可能不是故意这样做”?

c valgrind calloc
5个回答
3
投票

我知道我在使用calloc分配的内容之外访问内存,但我正在尝试了解实际发生的情况。

“实际发生的事情”没有明确定义;它完全取决于被覆盖的内容。只要您不覆盖任何重要的内容,您的代码就会按预期运行。

最终可能会破坏动态分配的其他数据。你可能最终破坏了一些堆簿记。

该语言不对数组访问强制执行任何类型的边界检查,因此如果您读取或写入数组的末尾,则无法保证将会发生什么。


2
投票

堆栈中的某些地址(?)是否仍然具有值100?

首先,calloc在堆上分配内存而不是堆栈。

现在,关于错误。

大多数情况下,程序运行时有足够的可用内存。但是,当您为x字节分配内存时,内存管理器会查找一些具有相同大小的内存空闲块(如果calloc请求更大的内存来存储一些辅助信息,则可能会更多),对此之后的字节没有任何保证。 chunk用于,甚至不保证它们不是只读的,或者可以由程序访问。

所以一切都会发生。如果内存只是等待你的程序使用它,没有什么可怕的事情发生,但如果你的程序中的其他东西使用了那个内存,那么这些值会变得混乱,或者最糟糕的是程序可能会因访问不应访问的内容而崩溃。

所以应该非常认真地对待valgrind错误。

C语言不需要对数组访问进行边界检查,并且大多数C编译器都不实现它。此外,如果你使用一些变量大小而不是常量值3,那么在编译期间数组大小可能是未知的,并且无法检查访问是否不受限制。


2
投票

这样做的行为就是所谓的undefined behavior。字面上任何事情都可能发生,或者根本没有。

即使你是愚蠢的,我给你额外的积分来测试Valgrind。

实际上,您可能会在数组后的内存空间中找到值100。

小心nasal demons


2
投票

对于在x[3]之后的空间分配的内容或未来将在那里写的内容,我们无法保证。 alinsoar提到x[3]本身不会导致未定义的行为,但您不应该尝试从那里获取或存储值。通常,您可能会毫无问题地编写和访问此内存位置,但编写依赖于分配到阵列之外的代码会让您在将来很难找到错误。

堆栈中的某些地址(?)是否仍然具有值100?

使用calloc或malloc时,数组的值实际上不在堆栈中。这些调用用于动态内存分配,这意味着它们被分配在称为“堆”的单独内存区域中。这允许您从堆栈的不同部分访问这些数组,只要您有指向它们的指针即可。如果数组在堆栈上,写入超出边界将有可能覆盖函数中包含的其他信息(例如在最坏的情况下返回位置)。


0
投票

你正在为3个整数元素分配内存但访问第4个元素(x[3])。因此,来自valgrind的警告信息。编译器不会抱怨它。

© www.soinside.com 2019 - 2024. All rights reserved.