请考虑以下事项:
int* x = calloc(3,sizeof(int));
x[3] = 100;
它位于函数内部。
当我编译和运行程序时,我没有收到任何错误,但是当我使用 valgrind 运行它时,我得到"大小为 4 的无效写入"。
我知道我正在访问一个我用calloc分配的内存位置之外的记忆位置,但我试图了解实际发生了什么。
堆栈(?)中的某个地址是否仍然具有值100?因为肯定有更多的可用内存,而不是我用calloc分配的内存。瓦尔格林德的错误更像是"嘿,你可能不是故意的"吗?
我知道我正在访问一个内存位置,而不是我用calloc分配的内存位置,但我试图了解实际发生了什么。
"实际发生什么"没有明确的定义;它完全取决于什么被覆盖。 只要不覆盖任何重要内容,代码就会按预期运行。
您最终可能会损坏动态分配的其他数据。 你最终可能会破坏一些堆簿记。
该语言不会对数组访问强制执行任何类型的边界检查,因此,如果您在数组末尾读取或写入,则无法保证会发生什么。
堆栈(?) 中的某个地址是否仍然具有值 100?
首先,calloc
在堆上分配内存而不是堆栈。
现在,关于错误。
当然,大多数情况下,程序运行时有足够的可用内存。但是,当您为x字节分配内存时,内存管理器会查找该确切大小的一些可用内存块(+如果请求更大的内存来存储一些辅助信息,则可能更多calloc
),无法保证该块之后的字节用于什么,甚至无法保证它们不是只读的或可以被您的程序访问。
所以任何事情都可能发生。如果内存只是在那里等待程序使用它,则不会发生任何可怕的事情,但是如果该内存被程序中的其他内容使用,则值将变得混乱,或者最糟糕的是,程序可能会因为访问不应该访问的内容而崩溃。
因此,应该非常认真地对待瓦尔格林德错误。
C语言不需要对数组访问进行边界检查,大多数 C 编译器也不实现它。此外,如果您使用了一些变量大小而不是常量值 3,则在编译期间数组大小可能是未知的,并且无法检查访问是否越界。
无法保证过去x[3]
的空间中分配了什么,或者将来会在那里写入什么。 Alinsoar提到x[3]
本身不会导致未定义的行为,但你不应该尝试从那里获取或存储值。通常,您可能能够毫无问题地编写和访问此内存位置,但是编写依赖于访问分配的数组之外的代码会为将来很难发现错误设置自己。
堆栈(?)中的某个地址是否仍然具有值100?
使用 calloc 或 malloc 时,数组的值实际上并不在堆栈上。这些调用用于动态内存分配,这意味着它们被分配到称为"堆"的单独内存区域中。这允许您从堆栈的不同部分访问这些数组,只要您有指向它们的指针。如果数组在堆栈上,则超出边界写入将有可能覆盖函数中包含的其他信息(例如在最坏的情况下返回位置)。
这样做的行为就是所谓的未定义行为。 从字面上看,任何事情都可能发生,或者什么都不发生。
我给你加分,用瓦尔格林德进行测试。
实际上,您可能会在数组之后的内存空间中找到值 100。
小心鼻魔。
您正在为 3 个整数元素分配内存,但访问第 4 个元素 (x[3]
)。因此,来自瓦尔格林德的警告消息。编译器不会抱怨它。