如果我在 calloc 分配的内存之外设置一个值会怎样?

What happens if I set a value outside of the memory allocated with calloc?

考虑以下几点:

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

它位于函数内部。

编译和 运行 程序时没有出现错误,但是当我使用 valgrind 运行 时,我得到 "Invalid write of size 4"。

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

堆栈中的某些地址(?)是否仍然具有值 100?因为肯定有比我用calloc分配的更多的可用内存。 valgrind 错误更多的是 "Hey, you probably did not mean to do that" 吗?

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

无法保证 space 过去 x[3] 分配的内容或将来会写入的内容。 alinsoar 提到 x[3] 本身不会导致未定义的行为,但您不应尝试从那里获取或存储值。通常,您可能能够毫无问题地写入和访问此内存位置,但是编写依赖于到达分配数组之外的代码会使您自己在将来很难发现错误。

Does some address in the stack(?) still have the value 100?

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

Does some address in the stack(?) still have the value 100?

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

现在,关于错误。

当然,当您的程序 运行 时,大多数时候都有足够的内存可用。但是,当您为 x 字节分配内存时,内存管理器会寻找一些该大小的空闲内存块(如果 calloc 请求更大的内存来存储一些内存,则可能更多辅助信息),无法保证该块之后的字节用于什么,甚至无法保证它们不是只读的或可以被您的程序访问。

所以任何事情都有可能发生。在这种情况下,如果内存只是等待它被您的程序使用,则不会发生任何可怕的事情,但是如果该内存被您程序中的其他东西使用,那么这些值就会变得混乱,或者最糟糕的是程序可能会由于访问了不应该访问的内容而崩溃。

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

C 语言不需要对数组访问进行边界检查,大多数 C 编译器也不会实现它。此外,如果您使用一些可变大小而不是常量值 3,则在编译期间数组大小可能是未知的,并且将无法检查访问是否超出范围。

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

用Valgrind测试我给你加分。

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

提防nasal demons.

I understand that I am accessing a memory place outside of what I have allocated with calloc, but I'm trying to understand what actually happens.

"What actually happens"定义不明确;这完全取决于被覆盖的内容。只要您不覆盖任何重要内容,您的代码就会按预期 出现 到 运行。

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

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