【问题标题】:Why realloc() in C changes memory?为什么 C 中的 realloc() 会改变内存?
【发布时间】:2018-04-14 11:53:47
【问题描述】:

我认为realloc() 函数会重新分配内存并且不会更改它。 在调试了一个我必须做的任务后,我意识到 realloc() 改变了内存中的一些元素并产生了错误。

于是我写了如下代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *a, *p;
    a = (int*)calloc(10, sizeof(int));
    for (int i = 0;i < 10; i++)
        a[i] = i;
    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);
    printf("\n");
    p = realloc(a, 20);
    p[10] = 10;
    for (int i = 0; i < 11; i++)
        printf("%d ", p[i]);
    printf("\n");
    for (int i = 0; i < 10; i++)
        printf("%d ", a[i]);

    return 0;
}

我得到以下输出

谁能解释为什么会发生这种情况?

我尝试使用malloc() 而不是calloc(),但现有数组也会改变。

【问题讨论】:

  • realloc() 指定的新大小以字节为单位。如果你想为 20 个int 提供新的存储空间,你需要做p = realloc(a, 20*sizeof(int))。如果 sizeof(int) 为 4,realloc(a, 20) 将调整大小为五个 int 的数组,并且访问元素 520 会给出未定义的行为。
  • 您还应该检查calloc()realloc() 调用是否成功。如果失败,他们会返回 NULL

标签: c pointers dynamic-memory-allocation realloc


【解决方案1】:

发生这种情况是因为您重新分配的项目少于 项,而不是最初使用calloc 分配的项目。混淆是由于callocmalloc/realloc 的签名略有不同。来电

a = calloc(10, sizeof(int));

sizeof(int)等于4的系统上分配10个sizeof(int)块,或40个字节,而

p = realloc(a, 20);

要求将该块的大小减少到 20 个字节。换句话说,calloc 会为您执行 sizeof 的乘法运算,而 reallocmalloc 则需要您自己执行乘法运算。

一旦您告诉 realloc 您只需要 20 个字节,任何超过第五个整数末尾的访问都是未定义的行为。

如果要将大小扩展到 20 ints,乘以 sizeof(int)

p = realloc(a, 20*sizeof(int));

【讨论】:

  • @AbhishekKeshri 它没有“工作”,它是未定义的行为,看起来像是“工作”。
【解决方案2】:

来自cppreference

重新分配由以下任一方式完成:

a) 扩展或收缩 ptr 指向的现有区域,如果 可能的。该区域的内容保持不变,直至较小 新的和旧的尺寸。如果区域扩大,内容 数组的新部分未定义。

b) 分配大小为 new_size 字节的新内存块,复制 大小等于新旧大小中较小的内存区域, 并释放旧块。

这取决于编译器的实现和您重新分配的大小。如果新分配的大小在没有fragment的情况下是不可占用的,那么realloc肯定会在不同的位置分配内存,这比释放已经用完的内存效率更高。

【讨论】:

    【解决方案3】:

    p = realloc(a, 20);

    在此语句中,您将 p 重新分配为 20/4 = 5。

    访问未定义的内存会导致undefined behavior。这意味着编译器可以以任何方式运行:程序崩溃、垃圾值、有时是正确的结果。

    这就是你在第 5 个元素之后得到垃圾值的原因。

    编辑到:p = realloc(a, 20*sizeof(int));

    【讨论】:

      【解决方案4】:

      语句a = (int*)calloc(10, sizeof(int)); 分配10x440 字节。假设从0x1000x140 位置。

          -----------------------------------------
         |     |    |    |   |    |    |      |    |
          -----------------------------------------
         0x100     ..      0x120                0x140
         a
      

      接下来,当您在同一 a 上执行 realloc() 时,例如 p = realloc(a, 20);,它不会添加 20 字节,它会将整个内存减少到 20 字节本身,即从 0x1000x120 现在当您访问p[10] = 10; 时,它越界,即您试图将数据放在0x140 位置附近,这会导致未定义的行为。

          --------------------
         |     |      |      | 
          --------------------
         0x100     ..      0x120 
         a                   
         p
      

      来自man 3 realloc

      realloc() 函数改变指向的内存块的大小 到 通过 ptr 到 size 字节。内容将在以下范围内保持不变 区域的开始,直到新旧尺寸的最小值。如果 新尺寸大于旧尺寸,增加的内存不会 初始化。

      如果你真的想将现有内存扩展20 字节,那么就这样做

      p = realloc(a ,20*sizeof(int));
      

      【讨论】:

        猜你喜欢
        • 2011-05-10
        • 2018-04-08
        • 2021-07-30
        • 2020-10-26
        • 1970-01-01
        • 2019-08-11
        • 1970-01-01
        • 2020-03-06
        • 1970-01-01
        相关资源
        最近更新 更多