为什么C中的realloc()会改变内存?

时间:2018-04-14 11:53:47

标签: c pointers dynamic-memory-allocation realloc

我认为realloc()函数会重新分配内存并且不会对其进行更改。 在调试了我必须做的赋值之后,我意识到realloc()改变了内存中的一些元素并创建了bug。

所以我写了下面的代码:

#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;
}

我得到了以下输出

enter image description here

有人可以解释为什么会发生这种情况吗?

我尝试使用malloc()代替calloc(),但现有数组也会发生变化。

4 个答案:

答案 0 :(得分:2)

这是因为您重新分配较少的项目,而不是最初分配给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 int s,请乘以sizeof(int)

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

答案 1 :(得分:1)

来自cppreference

  

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

     

a)扩展或收缩ptr指出的现有区域,如果   可能。该地区的内容保持不变   新旧尺寸。如果该区域扩大,则内容为   数组的新部分未定义。

     

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

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

答案 2 :(得分:0)

p = realloc(a, 20);

在此声明中,您将p重新分配为20/4 = 5.

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

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

将其修改为:p = realloc(a, 20*sizeof(int));

答案 3 :(得分:0)

语句<% Perk.all.each do |perk| %> <input type="checkbox", class="hidden" value="<%= perk.id %>" name="company[perk_ids][]" id="company_perk_ids_<%= perk.id %>"/> <label class="category-choice" for="company_perk_ids_<%= perk.id %>"> <% end %> 分配a = (int*)calloc(10, sizeof(int));,即10x4个字节。我们可以说从400x100位置。

0x140

接下来当你 ----------------------------------------- | | | | | | | | | ----------------------------------------- 0x100 .. 0x120 0x140 a realloc() a p = realloc(a, 20);时,20不会添加20个字节,它会将整个内存减少到0x100个字节,即从0x120p[10] = 10;,现在当您访问0x140时,它正在尝试将数据放在 -------------------- | | | | -------------------- 0x100 .. 0x120 a p 位置附近,导致未定义的行为。

man 3 realloc
来自20

  

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

如果你真的想要将现有内存扩展p = realloc(a ,20*sizeof(int)); 个字节,那么就像

一样
UUID contacId=(UUID) getArguments().getSerializable(ARG_CRIME_ID); 
mContact =ContactLab.get(getActivity()).getContact(contacId)
nameTextView.setText(mContact.getName());