Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如果free()知道数组的长度,为什么';我不能在我自己的代码中要求它吗?_C_Memory_Free_Malloc - Fatal编程技术网

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

C 如果free()知道数组的长度,为什么';我不能在我自己的代码中要求它吗?,c,memory,free,malloc,C,Memory,Free,Malloc,我知道,将动态分配数组的长度传递给操作它们的函数是一种常见的约定: void initializeAndFree(int* anArray, size_t length); int main(){ size_t arrayLength = 0; scanf("%d", &arrayLength); int* myArray = (int*)malloc(sizeof(int)*arrayLength); initializeAndFree(myArra

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

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);
}
void initializeAndFree(int*anArray,size\u t length);
int main(){
大小_t排列长度=0;
扫描频率(“%d”和排列长度);
int*myArray=(int*)malloc(sizeof(int)*arrayLength);
initializeAndFree(myArray,arrayLength);
}
void initializeAndFree(整数*数组,大小\u t长度){
int i=0;
对于(i=0;i
但是,如果我无法从指针获得分配内存的长度,那么当我给它的都是同一个指针时,
free()
“自动”如何知道释放什么呢?作为一名C程序员,为什么我不能参与到这项神奇的工作中去呢


free()
从何处获得免费(har-har)知识?

您无法获得它,因为C委员会在标准中没有要求

如果您愿意编写一些不可移植的代码,您可能有幸:

*((size_t *)ptr - 1)
或者可能:

*((size_t *)ptr - 2)

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

除此之外,标准没有提供这些数据外,真正的malloc/free实现通常会分配比您要求的更多的空间。例如,如果您要求12个字节,它可能会提供16个字节(请参阅,其中说明16是一个常用大小)。因此,它不需要知道您请求了12个字节,只需要它给了您一个16字节的块。

这取决于
malloc
实现者如何存储这些数据。通常,长度直接存储在分配的内存前面(也就是说,如果您想分配7个字节,实际上会分配7+x个字节,其中x个额外字节用于存储元数据)。有时,元数据存储在分配的内存之前和之后,以检查堆损坏。但是实现者也可以选择使用额外的数据结构来存储元数据

非标准的方法是使用。使用此函数将使代码不可移植。此外,文档还不清楚它将返回传递到
malloc()
的数字还是实际的块大小(可能更大)。

虽然可以获得内存分配器放置在分配块之前的元数据,只有当指针确实是指向动态分配块的指针时,这才有效。这将严重影响函数的实用性,函数要求所有传递的参数都是指向此类块的指针,而不是简单的自动或静态数组

关键是,通过检查指针来了解它所指向的内存类型是不可移植的。因此,尽管这是一个有趣的想法,但并不是一个特别安全的提议

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

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

// 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 ;
阅读后,我自己尝试了它,并且
ptr[-1]
确实存储了实际的内存(通常比我们要求的内存要多,可能是为了防止分段错误)

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

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

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

您可以分配更多内存来存储大小:

void my_malloc(size_t n,size_t size ) 
{
    void *p = malloc( (n * size) + sizeof(size_t) );
    if( p == NULL ) return NULL;
    *( (size_t*)p) = n;
    return (char*)p + sizeof(size_t);
}

void my_free(void *p)
{
    free( (char*)p - sizeof(size_t) );
}

void my_realloc(void *oldp,size_t new_size)
{
    // ...
}

int main(void)
{
    char *p = my_malloc( 20, 1 );
    printf("%lu\n",(long int) ((size_t*)p)[-1] );
    return 0;
}

为了回答关于DEL[]的问题,C++的早期版本实际上要求调用Dele[n]并告诉运行时大小,因此它不必存储它。可悲的是,这种行为被删除为“太令人困惑”


(详见D&E。)

我知道这条线有点旧,但我还是有话要说。有一个函数(或宏,我还没有检查库)malloc_usable_size()-获取从堆中分配的内存块大小。手册页声明它只用于调试,因为它输出的不是您请求的号码,而是它分配的号码,这个号码稍大一些。注意,这是GNU扩展


另一方面,它甚至可能不需要,因为我相信要释放内存块,您不必知道它的大小。只需删除负责块的句柄/描述符/结构。

我认为长度必须存储在前面。您需要知道缓冲区的大小,才能知道在哪里可以找到任何后续元数据。如果大小在尾随元数据中,则在获取该数据时存在鸡/蛋问题。而不是“必须”。可以想象,分配器可以单独存储一个哈希表,该哈希表将指针映射到免费的大小。备选方案:拥有大量具有各种桶大小的竞技场,分配大小可以根据指针是否在该竞技场的区域内来确定。我个人将简化为
((size_t*)ptr)[-1]
。@Chris Lutz:[-1]表示什么?这是假装指针是一个数组,并在开始前一个元素建立索引。@Simon:Oops。嗯。谢谢我以为那是在声明一个类型。我想当我看到所有的*和('s.=p您能详细说明这将在哪些平台上工作吗?还要注意,
int length
是错误的。数组长度、偏移量和类型大小以及其他类似的东西都是
size\u t
类型,在
stddef.h
stdio.h
stdlib.h
string.h
中定义aders.
大小之间的主要区别_
void my_malloc(size_t n,size_t size ) 
{
    void *p = malloc( (n * size) + sizeof(size_t) );
    if( p == NULL ) return NULL;
    *( (size_t*)p) = n;
    return (char*)p + sizeof(size_t);
}

void my_free(void *p)
{
    free( (char*)p - sizeof(size_t) );
}

void my_realloc(void *oldp,size_t new_size)
{
    // ...
}

int main(void)
{
    char *p = my_malloc( 20, 1 );
    printf("%lu\n",(long int) ((size_t*)p)[-1] );
    return 0;
}