在指向动态声明的数组元素的指针上调用 free

Calling free on a pointer to an element of an array declared dynamically

当我运行以下代码时:

int main(int* argc, char** argv) {
    int* array = malloc(5 * sizeof(int));
    free(array + 3);
}

我收到错误 pointer being freed was not allocated。我的直觉是,free 并没有试图释放 array 的第四个元素,而是试图释放在其最后一个元素之后 3*sizeof(int) 字节的东西。这个对吗?如果是这样,那么为什么会发生这种情况?执行该程序所产生的行为是否总是可预测的,或者它是否未定义特定于实现?

malloc分配一块内存。

您只能取消分配 (free) 此块。您不能释放单个元素或块的一部分。

您可以重新分配(realloc)此块以使其变大或变小。

来自 free() 的规范:

Synopsis

#include <stdlib.h>
void free(void*ptr);

Description

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

因此,您试图做的是未定义的行为

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf

free 希望您使用从 malloc 返回的完全相同的地址,否则可能会发生任何事情。 malloc 调用为每个调用分配一个完整的段,在本例中为 5 int 大。释放这个段的一部分没有意义,堆不是这样工作的。

堆首先分配一个段header,这是包含大小等的内部信息。然后header,所有数据。此 header 部分对程序员不可见,它的实现方式是 OS and/or C 库特定的。

事实上,在您的情况下,您将一个位于 3*sizeof(int) 字节的地址传递到段的数据部分,这不是有效地址,因为 free 需要 malloc 使用的初始地址为了知道该段的内部 header 从哪里开始。当您将错误的地址传递给它时,它可能会获取随机数据的其他部分并将其视为 header。行为未定义。

(但是,您可以将空指针传递给 free(),这保证是 no-op。)