realloc()
的一个有趣特性是,它以某种方式知道数据复制或扩展分配的内存时的时长。
我读到发生的事情是幕后存在一些关于指针(包含它分配的内存大小)的元信息,通常紧接在指针所指向的地址之前(但当然,需要实现)
所以我的问题是,如果存储了这样的数据,为什么不通过API公开,那么像C字符串这样的东西就不必寻找\0
来知道字符串的结尾是。
也可能有数百种其他用途。
答案 0 :(得分:3)
正如你自己所说,它受制于标准库的内存管理器的实现。
C没有这种功能的标准,可能是因为一般来说C设计简单(但也提供了很多功能)。
话虽如此,除了用于调试内存分配的功能之外,这种类型的功能并没有太多用处。
一些编译器do provide this type of functionality(specifically memory block size),但很清楚它只是为了调试。
编写自己的内存管理器并不常见,允许您完全控制分配,甚至可以对其他库组件进行假设。正如您所提到的,您的实现可以在标头中的某处存储分配的大小,字符串实现可以引用该值而不是遍历\0
终止的字节。
答案 1 :(得分:2)
此信息并不总是准确的
在Windows上,大小向上舍入为至少8的倍数
realloc
对此很好,因为它只关心分配的大小,但您不会获得所请求的大小。
答案 2 :(得分:1)
这里值得了解分配器的工作原理。例如,如果您使用伙伴分配器,它会以预定大小分配块。为简单起见,假设2的幂(现实世界的分配器通常使用更紧凑的大小)。
在这种简化的情况下,如果你调用malloc
并请求19字节的内存供你个人使用,那么分配器实际上会给你一个32字节的内存块。它并不关心它给你提供的超过你需要的东西,因为它仍然满足你的基本要求,给你一些大于或大于你需要的东西。
这些块大小通常以某种方式存储在某个地方,用于通用分配器,它可以处理可变大小的请求,以便能够释放块并执行诸如将无空块合并在一起并将它们分开的事情。然而,他们正在识别块大小,而不是您的请求的大小。因此,您无法使用该块大小来查看字符串应该结束的位置,例如,因为根据您的说法,您需要一个19字节而不是32字节的字符串。
realloc
也不关心您请求的19字节大小。它工作在位和字节的级别,因此它将整个块的内存值复制到一个新的,更大的块(如果必须的话)。
因此,这些类型的块大小通常对于实现数据结构这样的东西没有用。对于这些,您希望以与您请求的内存量成比例的数据大小工作,这是许多分配器甚至懒得存储的东西(它们不需要为了满足它们的效率需要而工作)。因此,通常由您来跟踪与某种形式的软件逻辑一致的大小(像一个空终结符的哨兵是一种形式)。
至于为什么在标准中没有查询这些大小的原因,可能是因为需要知道它是一种相当模糊,低级别的需求,因为它与你实际的内存量无关要求合作。我经常希望它能用于一些非常低级的调试需求,但是我已经使用了平台/编译器特定的替代方案,而且我发现它们并不像我想象的那样方便(即使对于低级调试)。
答案 3 :(得分:0)
你问:
如果存储了这样的数据,为什么不通过API公开,所以像C字符串这样的东西就不必查找\ 0来知道字符串结尾的位置。
您可以分配足够的内存,并且可以容纳100个字符,但您可以使用该内存来容纳长度仅为5个字符的字符串。如果您依赖指针元数据,则会得到错误的结果。
char* cp = malloc(100);
strcpy(cp, "hello");
您需要终止空字符的第二个原因是当您使用堆栈内存创建字符串时。
char str[100] = "hello";
如果没有终止空字符,您将无法确定str
中保存的字符串的长度。
你说:
也可能有数百种其他用途。
除了说自定义内存分配器通常提供对元数据的访问之外,我对此没有很好的回应。不在标准库中包含此类API的原因对我来说并不明显。