为了说明一些其他人已经说过的内容,请尝试执行以下程序:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char** argv) {
char* b = (char*)malloc(0x01020304);
strcpy(b, "ABCDEFG");
for (int index = -16; index < 16; index++) {
printf("%02x ", (unsigned char) *(b + index));
}
free(b);
return 0;
}
程序的输出(基本上是缓冲区位置周围内存的十六进制转储):
01 00 00 00 04 03 02 01 4e 00 00 00 fd fd fd fd 41 42 43 44 45 46 47 00 cd cd cd cd cd cd cd cd
您可以看到缓冲区的内容(41 42 43 44 45 46 47 是十六进制的 ABCDEFG)。所以,在这个例子中,“b”只是指向内存中的那个位置,但在那之前还有更多的东西。就在内容之前有四个“fd”字节(与问题无关,但很有趣)。这是一个“栅栏”,用于检查您的程序是否写入缓冲区边界之外。例如,如果您执行 *(b - 1) = 'A' 之类的操作,内存管理器会在释放块时检测到这一点,因为它会看到栅栏已被修改。在缓冲区的末尾有一个类似的栅栏(比这个更可能被覆盖)。
但除此之外,您还可以在此之前看到缓冲区本身的长度(04 03 02 01)。您必须考虑到 intel 对数据使用 little-endian 表示法,因此内存中的大小与我们人类的预期相反。
因此,当您在缓冲区上调用 free 时,内存管理器只是从您作为参数传递的位置向后移动并计算它必须释放的缓冲区的大小。指针的类型并不重要。
我在 Visual Studio 2019 中执行了此操作并进行了调试,因此如果您在另一个平台上自己尝试,您的里程可能会有所不同(您甚至可能无法找到块大小,因为该信息可能存储在内存中的其他位置以及什么您之前的缓冲区是指向该信息的指针),但基本思想是相同的:内存管理器存储有关您正在分配的块的大量信息,例如块大小,因此指针的类型您在免费中使用并不重要。