问题:如果我有一个指向“ints”结构的指针(如下所示),并且将其强制转换为 void 并返回,这是否意味着我不能再释放它了?free 如何跟踪分配大小?
typedef struct ints
{
int size;
int *data;
}
ints;
static void dev_array_cleanup(void *array, array_type type)
{
switch(type)
{
case INT:
ints *i = (ints*) array;
free(i->data);
free(i);
i = NULL;
break;
}
}
static void* dev_array_set(void *array, int size, array_type type)
{
void *p;
switch(type)
{
case INT:
ints *i = (ints*) malloc(sizeof(ints));
i->size = size;
i->data = (int*) malloc(size * sizeof(int));
p = (void*) i;
break;
}
return p;
}
是的,你可以这样
free
做。事实上,free
为了避免内存泄漏,你必须(最终)这样做。free
不关心指针指向的类型 - 它接受void*
。并且任何对象指针都可以转换为
void*
。因此,您可以简单地调用
free
指针(无论是否转换)。这是由运行时库内部完成的(基于块的地址),并且不依赖于类型。
附注:
您不应该转换结果
malloc
- 请参见此处:我应该转换 malloc 的结果吗(在 C 语言中)?。内存管理例程的实现以各种方式跟踪内存。一种方法是,在分配内存时,例程会在返回给客户端的内存之前将一些数据放入内存中。例如,如果调用者请求 500 字节,则内存管理软件可能会在地址X处分配 504 字节,将分配的大小放在地址X处,然后将地址X +4 返回给调用者。
当使用参数Y
free
调用时,它会计算X = Y −4 并查看地址X来查找大小。另一种方法是内存管理例程可以维护一个单独的数据库,该数据库记录当前未完成的所有分配的大小。
free
调用时,它会在这个数据库中查找其参数以查看大小。另一种方法可能是将某个已知区域中的所有内存分配为固定大小的块,例如每个块 16 字节。(其他区域可能使用不同的大小。)因此,当
free
使用该已知区域内的地址调用时,它知道大小为 16 字节。将指针转换为其他类型不会改变它指向的内存。将指针传递给时
free
,它会被转换回void *
(因为free
声明为)void free(void *)
。只要接收到与(或其他分配例程之一)free
返回的相同地址,它就会起作用。malloc
由于 wohlstad 已经直接回答了这个问题,因此还需要对风格和最佳实践进行进一步的说明。
malloc
,如果不成功则处理它。p
是不必要的,而且如果type
不是,则未初始化是危险的INT
。附加大小的数组的想法在 C 中并不是特别惯用。有意义的是实现类似 C++
std::vector
或 Java 的东西ArrayList
:具有恒定时间访问属性的可扩展数组。并且使用空指针和明智地应用强制类型转换,可以使其变得合理通用。
一个非常不完整的实现来演示: