【问题标题】:Why isn't realloc shrinking the array?为什么 realloc 不缩小数组?
【发布时间】:2014-07-02 01:36:05
【问题描述】:

我无法减小动态创建的数组的大小。这是我的main 函数的样子:

int main(void) {
    // Intialize big array
    int * a = (int *)malloc(10*sizeof(int));
    assert(a);
    // Fill it with squares
    for (int i = 0; i < 10; ++i)
        a[i] = i*i;
    // Expected to print 64
    printf("%d\n", a[8]);
    // Shrink the big array
    int * b = (int *)realloc(a, 5*sizeof(int));
    assert(b);
    // Expected to cause SEGFAULT
    printf("%d\n", b[8]);
    return 0;
}

除了printf("%d\n", b[8]); 行之外,一切正常,因为它打印64,但没有像我预期的那样导致 SEGFAULT 错误。为什么?

我想我遗漏了一些简单的东西,因为我已经看到很多与使用realloc 缩小内存有关的 SO 问题,但他们都说这是可能的。

我正在使用带有 GCC 4.8.2 的 Ubuntu 14.04 并使用 -std=c99 选项对其进行编译。

【问题讨论】:

  • 最近几天有人问过这个问题,或者几乎相同的问题——但我无法立即找到它。尽管realloc() 将内存返回到其内部可用内存池,并且任何对其进行读取或写入的尝试都会导致未定义的行为,但它通常不会取消映射内存,因此访问它通常不会直接导致崩溃——但是从释放的内存中读取是非常糟糕的做法,而写入释放的内存则更糟糕。
  • {Rewrite] 不确定建议的副本。提议的副本与realloc()malloc() 无关。目前,我没有一个好的副本可以指出,但我还没有进行彻底的搜索。我怀疑我记得的“接近重复”已被其 OP 删除。总的来说,让这个保持打开状态。
  • 是的,这个问题和建议的副本都是关于在数组边界之外读取和写入数据 - 在这种情况下是动态分配的,在另一个情况下是正常的(全局变量)。在这个程度上,它们是重复的。但我认为,在分配空间缩小之前,负索引与访问合法内容的重点有所不同。我不会对重复的闭包提出异议,但我更愿意找到一个更明确地解决动态分配的内存和收缩的重复。

标签: c memory malloc realloc shrink


【解决方案1】:

您正在访问未分配的空间。那是未定义的行为。在最坏的情况下,就像现在一样,它仍然有效。不保证会发生段错误。

【讨论】:

  • @frostnational 不要依赖 realloc 将内存保持在同一地址
【解决方案2】:

Realloc 只会标记剩余的缓冲区可用于未来的 malloc 操作。它是 UB,如果该缓冲区上没有发生 malloc,您仍然可以访问该缓冲区,这就是您的情况。您很幸运在访问未分配的内存时没有遇到段错误。

【讨论】:

    【解决方案3】:

    它是未定义的,当你跟随它时它可能会崩溃,这取决于你正在访问的内存是否属于你的进程:

    int i;
    int a[5];
    for(i=0;i<10;i++)
      printf("%d\n", a[i]);
    

    你必须自己检查。

    【讨论】:

      【解决方案4】:

      第二个printf 调用中的b[8] 访问未分配的内存并调用未定义的行为。这就是基本未定义行为的含义。结果是不可预测的。它可能看起来工作正常,但下一次它可能会崩溃。这里几乎没有其他需要考虑的事情 -

      • malloc 可能无法分配内存,因此使用assert 宏检查其返回值是错误的。 assert 应该用于调试不可能或错误的代码,例如访问超出范围的数组。

      • 您不应该转换malloc 的结果。 Do I cast the result of malloc?

      • realloc 可能无法重新分配像malloc 这样的内存块。当它失败时,它返回NULL 并保持旧块不变。这意味着您将失去对旧内存块的处理,从而导致它泄漏。在调用realloc 之前,您应该将指向旧块的指针存储在一个变量中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-17
        • 2021-10-14
        • 2019-08-04
        • 1970-01-01
        • 2015-03-19
        • 2012-10-01
        • 2013-09-23
        相关资源
        最近更新 更多