从 malloc 类型更改指针类型并释放它。会导致内存泄漏吗?
change pointer type from malloc type and free it. Does it lead to memory leak?
我使用 malloc 分配指针类型使用的内存。然后我强行修改指针类型。使用 free func 释放内存块。我想知道是否发生内存泄漏?
我以为 memroy 按指针类型是免费的。 “int *b”比“char *a”具有更宽范围的内存块。我编译以下代码并 运行 它。没有期望发生。有人能告诉我发生了什么事以及为什么吗?
#include <stdlib.h>
int
main(int argc, char **argv) {
char *a = (char*)malloc(sizeof(char));
int *b = (int*)a;
free(b);
}
malloc
系列中的例程跟踪它们保留的所有内存,包括大小。当您将地址传递给 free
时,例程会在其记录中查找地址并释放为其分配的 space 数量。
free
只传递了一个地址。它没有有关调用者用作参数的指针类型的信息。因为 free 声明为 void free(void *)
,任何传递给它的指针都会自动转换为 void *
,并且 free 只接收 void *
,而不接收任何来自 int *
的信息或其他类型。
为了进一步说明其他人已经说过的话,请尝试执行以下程序:
#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)。您必须考虑到英特尔对数据使用小端表示法,因此内存中的大小与我们人类期望的大小相反。
因此,当您在缓冲区上调用 free 时,内存管理器只是从您作为参数传递的位置向后移动,并计算它必须释放的缓冲区的大小。指针的类型并不重要。
我在 Visual Studio 2019 年执行了这个并进行了调试,所以如果你自己在另一个平台上尝试,你的里程可能会有所不同(你甚至可能无法找到块大小,因为该信息可能存储在某个地方内存中的其他内容以及缓冲区之前的内容是指向该信息的指针),但基本思想是相同的:内存管理器存储有关您正在分配的块的大量信息,例如块大小,所以您在 free 中使用的指针类型并不重要。
我使用 malloc 分配指针类型使用的内存。然后我强行修改指针类型。使用 free func 释放内存块。我想知道是否发生内存泄漏?
我以为 memroy 按指针类型是免费的。 “int *b”比“char *a”具有更宽范围的内存块。我编译以下代码并 运行 它。没有期望发生。有人能告诉我发生了什么事以及为什么吗?
#include <stdlib.h>
int
main(int argc, char **argv) {
char *a = (char*)malloc(sizeof(char));
int *b = (int*)a;
free(b);
}
malloc
系列中的例程跟踪它们保留的所有内存,包括大小。当您将地址传递给 free
时,例程会在其记录中查找地址并释放为其分配的 space 数量。
free
只传递了一个地址。它没有有关调用者用作参数的指针类型的信息。因为 free 声明为 void free(void *)
,任何传递给它的指针都会自动转换为 void *
,并且 free 只接收 void *
,而不接收任何来自 int *
的信息或其他类型。
为了进一步说明其他人已经说过的话,请尝试执行以下程序:
#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)。您必须考虑到英特尔对数据使用小端表示法,因此内存中的大小与我们人类期望的大小相反。
因此,当您在缓冲区上调用 free 时,内存管理器只是从您作为参数传递的位置向后移动,并计算它必须释放的缓冲区的大小。指针的类型并不重要。
我在 Visual Studio 2019 年执行了这个并进行了调试,所以如果你自己在另一个平台上尝试,你的里程可能会有所不同(你甚至可能无法找到块大小,因为该信息可能存储在某个地方内存中的其他内容以及缓冲区之前的内容是指向该信息的指针),但基本思想是相同的:内存管理器存储有关您正在分配的块的大量信息,例如块大小,所以您在 free 中使用的指针类型并不重要。