如果free()知道我的数组的长度,为什么我不能在我自己的代码中要求它?

Chr*_*per 44 c memory malloc free

我知道将动态分配的数组的长度传递给操作它们的函数是一种常见的约定:

void initializeAndFree(int* anArray, size_t length);

int main(){
    size_t arrayLength = 0;
    scanf("%d", &arrayLength);
    int* myArray = (int*)malloc(sizeof(int)*arrayLength);

    initializeAndFree(myArray, arrayLength);
}

void initializeAndFree(int* anArray, size_t length){
    int i = 0;
    for (i = 0; i < length; i++) {
        anArray[i] = 0;
    }
    free(anArray);
}
Run Code Online (Sandbox Code Playgroud)

但是如果我无法从指针中获取已分配内存的长度,那么free()当我提供的内容完全相同时,"自动"知道如何解除分配?作为一名C程序员,为什么我不能进入魔术?

从哪里free()获得免费(har-har)知识?

Mat*_*hen 31

除了Klatchko关于标准没有提供它的正确观点之外,真正的malloc/free实现通常会分配更多的空间然后你要求.例如,如果你要求12个字节,它可以提供16个字节(参见A Memory Allocator,它指出16是一个常见的大小).所以它不需要知道你要求12个字节,只是它给你一个16字节的块.


R S*_*hko 19

你不能得到它,因为C委员会不要求在标准中.

如果你愿意写一些非便携式代码,你可能会有运气:

*((size_t *)ptr - 1)
Run Code Online (Sandbox Code Playgroud)

或者可能:

*((size_t *)ptr - 2)
Run Code Online (Sandbox Code Playgroud)

但是否有效将取决于您正在使用的malloc的实现存储该数据的确切位置.

  • 我个人简化为`((size_t*)ptr)[ - 1]. (5认同)

Cli*_*ord 8

虽然有可能获得该内存分配名额分配的内存块之前的元数据,这只会工作,如果指针是一个真正的指向动态分配的内存块.这会严重影响函数的效用,要求所有传递的参数都是指向这些块的指针,而不是简单的自动或静态数组.

重点是检查指针没有可移植的方式来知道它指向的内存类型.因此,虽然这是一个有趣的想法,但它并不是一个特别安全的主张.

一种安全且便携的方法是保留分配的第一个字以保持长度.GCC(可能还有一些其他编译器)支持一种使用零长度数组结构实现此方法的非可移植方法,与便携式解决方案相比,这有点简化了代码:

typedef tSizedAlloc
{
    size_t length ;
    char* alloc[0] ;   // Compiler specific extension!!!
} ;

// Allocating a sized block
tSizedAlloc* blk = malloc( sizeof(tSizedAlloc) + length ) ;
blk->length = length ;

// Accessing the size and data information of the block
size_t blk_length = blk->length ;
char*  data = blk->alloc ;
Run Code Online (Sandbox Code Playgroud)


N 1*_*1.1 8

在阅读了Klatchko的回答之后,我自己尝试了它并ptr[-1]确实存储了实际的内存(通常超过我们要求的内存以防止分段错误).

{
  char *a = malloc(1);
  printf("%u\n", ((size_t *)a)[-1]);   //prints 17
  free(a);
  exit(0);
}
Run Code Online (Sandbox Code Playgroud)

尝试使用不同的大小,GCC按如下方式分配内存:

最初分配的内存是17个字节.
分配的内存比请求的大小多5个字节,如果请求更多,则分配8个字节.

  • 如果size为[0,12],则分配的内存为17.
  • 如果size为[13],则分配的内存为25.
  • 如果size为[20],则分配的内存为25.
  • 如果size为[21],则分配的内存为33.