请考虑以下内容:
int* x = calloc(3,sizeof(int));
x[3] = 100;
位于函数内部。
编译和运行程序时没有错误,但是使用valgrind运行该程序时,出现“大小为4的无效写入”。
我了解我正在访问用calloc分配的内存之外的存储空间,但是我试图了解实际发生的情况。
堆栈(?)中的某些地址是否仍为100?因为肯定有比我用calloc分配的更多的可用内存。 valgrind错误更像是“嘿,您可能不是故意这么做的”吗?
答案 0 :(得分:3)
我知道我正在访问的内存空间超出了我用calloc分配的内存空间,但是我试图了解实际发生的情况。
“实际发生的事情”没有明确定义;这完全取决于被覆盖的内容。只要您不覆盖任何重要内容,您的代码就会出现以按预期运行。
您可能会破坏其他动态分配的数据。您可能会破坏一些堆簿记。
该语言不会对数组访问进行任何形式的边界检查,因此,如果您在数组末尾进行读取或写入操作,则无法保证会发生什么。
答案 1 :(得分:2)
无法保证x[3]
之后的空间分配了什么,或者将来将写入什么。 alinsoar提到x[3]
本身不会引起未定义的行为,但是您不应尝试从那里获取或存储值。通常,您可能可以毫无问题地编写和访问该内存位置,但是编写依赖于到达已分配数组之外的代码的代码将使您自己将来很难发现错误。
堆栈(?)中的某些地址是否仍为100?
使用calloc或malloc时,数组的值实际上不在堆栈上。这些调用用于动态内存分配,这意味着它们被分配在称为“堆”的单独的内存区域中。这使您可以从堆栈的不同部分访问这些数组,只要您有指向它们的指针即可。如果数组在堆栈中,则超出界限可能会覆盖函数中包含的其他信息(例如在最坏的情况下,返回位置)。
答案 2 :(得分:2)
堆栈(?)中的某些地址是否仍为100?
首先,calloc
在堆而不是堆栈上分配内存。
现在,关于错误。
在大多数情况下,您的程序运行时可以确保有足够的可用内存。但是,当您为 x 个字节分配内存时,内存管理器会寻找一些确切大小的空闲内存(如果calloc
请求更大的内存来存储一些辅助信息,则可能会更多) ,没有关于该块后面的字节用于什么目的的保证,甚至没有保证它们不是只读的或不能被您的程序访问的保证。
所以什么都可能发生。在这种情况下,如果只是内存在等待程序使用,就不会发生可怕的事情,但是,如果该内存被程序中的其他人使用,则值将被弄乱,否则所有程序都可能变坏由于访问了不应访问的内容而崩溃。
因此应非常认真地对待valgrind错误。
C语言不需要对数组访问进行边界检查,并且大多数C编译器都没有实现它。此外,如果您使用一些可变大小而不是常量3,那么在编译过程中数组大小可能是未知的,并且将无法检查访问是否不受限制。
答案 3 :(得分:2)
这样做的行为就是所谓的undefined behavior。 从字面上看,任何事情都会发生,或者什么都不会发生。
即使您很笨,我也为您提供了使用Valgrind进行测试的额外要点。
实际上,您可能会在数组之后的内存空间中找到值100。
提防nasal demons。
答案 4 :(得分:0)
您正在为3个整数元素分配内存,但正在访问第4个元素(x[3]
)。因此,来自valgrind的警告消息。编译器不会对此抱怨。