缩小C中的整型数组

12

刚开始学习C语言时遇到了以下问题:

我需要在C语言中缩小整数数组,删除末尾的元素。通过删除,我的意思是释放内存。常见的答案是为较小的数组分配新内存,之后将原始数组的所有项(-要删除的项)复制到新分配的内存中,然后使用free()释放原始数组。

由于我必须处理非常大的数组,我宁愿跳过复制部分。

是否可以创建一个指向“原始数组接近末尾”的指针变量,其大小为“数组末尾-接近末尾”,然后释放该指针?

提前感谢


1
你可以使用 realloc 来缩小内存。虽然不是所有的实现都能保证,但有些实现会直接返回你传入的原始指针,而不进行任何复制。 - cnicutar
你考虑过使用realloc吗? - Keith Miller
realloc函数会释放掉末尾被删除的元素吗?我不知道如何测试这个问题...顺便说一下,谢谢你的快速回复! - Joeri van Veen
1
回答你的问题的一部分,free() 函数不可能通过传递一个指针“接近末尾”来释放内存块的一部分。那几乎肯定会导致崩溃或堆损坏。 - Blastfurnace
对于EDIT部分的注释:在将数据数组传递给此函数之前,您是否已经正确地使用malloc进行了内存分配? - SirDarius
显示剩余2条评论
4个回答

6

来自C标准库的realloc函数可能是您想要的。

在您的情况下,由于内存管理器没有理由分配新的内存区域,因此很可能不会执行任何复制操作。系统只能将旧大小和新大小之间的差异作为可用内存回收。

如果您使数组变得更大,则会发生复制,因为malloc等函数不能保证“当前”区域后面的内存实际上是空闲的。如果是这样,当前内存分配将扩展。 否则,需要找到一个更大的可用内存区域,并且可以在内存中的任何位置进行分配。


1
@JimBalter:realloc例程未定义将释放的内存用于新分配。它是否这样做取决于实现。malloc系列例程很难实现得好,因为它必须服务于各种应用程序,并在时间和内存之间进行权衡。花费额外的空间和时间来跟踪从大型分配中释放的少量内存可能不是高效的。 - Eric Postpischil
1
@EricPostpischil 我并没有说过它是如何定义的。我编写了几个商业级别的malloc/realloc,并研究了其他人的代码,深知它们是如何实现的。它根本不是“可能不会”释放内存...绝大多数可用的realloc都会这样做。而未能跟踪从大型分配中释放的内存会导致内存泄漏。当然,将稍小尺寸的realloc视为noop是一种选择,但足够释放缓冲区的空间将可供重用。 - Jim Balter
1
如果你使用malloc分配了一个大缓冲区,然后将其realloc到稍小的大小,那么realloc可能只是一个空操作,使分配的大小保持不变。但这仅适用于小差异,而不是大差异。(当然,实际上并非“按定义”执行。) - Jim Balter
1
@JimBalter:该实现不会丢失从大型分配中释放的少量内存的跟踪。它将简单地将其与大型分配一起保存。在整个分配被释放或另一个重新分配将请求的空间缩短到实现认为值得分割内存之前,该内存将不可用于重用。您报告的经验不足以作出realloc使得可释放内存可用的无保留声明。这取决于具体实现。 - Eric Postpischil
1
@JimBalter:从规范中推断行为是工程,而不是拘泥小节。假设没有文档的良好实现会导致错误。为了提高性能而交换少量内存(特别是当会计成本超过释放空间大小时净消极)并不是低质量的;而是针对性能进行优化。 - Eric Postpischil
显示剩余7条评论

2
你有没有考虑使用 realloc ?它是与内存分配相关的函数。
int main(void)
{
    int *array = NULL, *tmp;

    if(!(array = malloc(5 * sizeof(int)))) return 1;
    if(!(tmp = realloc(array, 2*sizeof(int)))) 
    {
        free(array);
        return 1;
    }
    array = tmp;
}

你可以不使用tmp指针,仅使用 array = realloc(array, 2 * sizeof(int))),但这可能会在以后出现问题。


0

可以设计一个内存管理器来实现这一点,但是常用的内存管理器都没有这个属性。您可以编写自己的内存管理器并将其用于这些数组。


0

我会使用realloc。Realloc可能会复制内存,但这仍然比自己编写内存管理来解决复制问题更高效。

有人会告诉你,当结果大小较小时,没有良好行为的C库不会复制。他们可能是对的。然而,我不使用或编写商业C库,所以就我而言,这个说法没有证据支持。


除了特殊情况下的调试选项防止释放任何内存外,所有商业库的realloc操作都会避免在大小缩小(或保持不变)时进行复制...为什么不这样做呢? - Jim Balter
同意;尽管据我所知这并不是有保证的/在规范中。 - Tom
人们一直在谈论规范的保证,以回应我的评论,但我的评论并没有涉及到这一点。规范并不保证 malloc 函数只会返回 NULL。理解规范很重要,但如果仅仅了解规范,那就是纠缠细节,而不是工程实践。 - Jim Balter
我不反对任何特定的观点,如果你给我同样的礼貌,我保证不曲解你的意思。 - Tom
我只是想指出,当我谈论“所有商业库reallocs”时,关于规范的评论是无关紧要或草人论。当然,在规范中没有保证realloc不会复制...也没有保证它会成功...但对于实践程序员来说,这根本不重要。 - Jim Balter
你错了。首先,我认为你误解了我的原始评论;它并不是要指责你。它只是为了说明当使用realloc时可能无法实现预期的行为。其次,关于“所有商业库”是否按照你所描述的方式实现realloc存在一些争议;你没有以任何方式支持你的说法。最后,你声称我的规范断言对于实践程序员来说并不重要,这也不是你可以真实地声称的。你在批评我的观点时没有支持你的观点! - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接