【问题标题】:Problems with realloc, makes program crashrealloc 的问题,导致程序崩溃
【发布时间】:2018-09-13 07:07:31
【问题描述】:

您好,我在 c 中实现了一个智能向量,但我在重新分配缓冲区时遇到了问题。

这是包含数组及其信息的结构:

struct _vector
{
    item* vec;
    size_t elements;
    size_t size;
};

item 只是一个 typedef,在这种情况下恰好是 int。 我做了几个函数来管理数组,但是应该调整它大小的那个给我带来了问题。

(顺便说一下,Vector也是struct _vector*的typedef)

这是函数:

void insertVector(const Vector vec,const int pos,const item a)
{
    if(vec->elements==vec->size)
    {
        item* temp=realloc(vec->vec,(vec->size*2)*sizeof(item));
        if(temp==NULL)
        {
            puts("Error: space unavailable");
            return;
        }
        //vec->vec=realloc(vec->vec,(vec->size*2)*sizeof(item));
        vec->vec=temp;
        vec->size*=2;
    }
    int size=vec->elements;
    if(pos>=0&&pos<=size)
    {
        for(int i=size;i>pos;i--)
        {
            vec->vec[i]=vec->vec[i-1];
        }
        vec->vec[pos]=a;
        vec->elements+=1;
        printf("size is %lu\nelements are %lu\n",vec->size,vec->elements);
    }
}

我只是移动内容为新元素腾出空间,它工作正常,问题是重新分配数组时。 当有效元素的数量等于数组的实际大小时, 我做了一个 realloc 以使实际大小加倍。 一旦 if 激活,尽管 realloc 使程序崩溃并出现以下错误:释放对象的校验和不正确。

问题出在 if 中,因为它仅在大小和元素相等时崩溃,如果我注释掉该部分,一切正常 我不知道会是什么。

编辑: 我用来创建和初始化我正在使用的实例的函数是:

Vector newVector(void)
{
    Vector new=malloc(sizeof(*new));
    new->vec=NULL;
    new->elements=0;
    new->size=0;
    return new;
}

和

void initVector(const Vector vec,const size_t size) 
{
    vec->vec=calloc(size,sizeof(item));
    vec->elements=size;
    vec->size=size*2;
}

【问题讨论】:

  • 如果你注释掉代码并且它神奇地工作,那通常是UB的标志
  • @yano 如果它崩溃了,那肯定是 UB :) OP 在问为什么......我猜需要 minimal reproducible example
  • 您的 for 循环从 i=size 开始,我怀疑 vec[size] 超出范围...但代码中可能还有未显示的 UB。
  • @yano vec[size] 将在 realloc 之后的范围内。 @Adonai 当你传递给insertVector 时,你是如何初始化vec 的?
  • 如果vec-&gt;vec的第一个init是一个静态数组(不是动态分配的)那么问题就说明了。

标签: c arrays realloc


【解决方案1】:

根据您的评论

我创建了一个新的向量设置,将每个字段归零,然后我使用了这个函数:

void initVector(const Vector vec,const size_t size) 
{ 
    vec->vec=calloc(size,sizeof(item));
    vec->elements=size;
    vec->size=size*2; 
}

我认为您错误地处理了元素的大小和数量。这 initVector 函数只是为 vec-&gt;vec 数组分配内存,所以 vec-&gt;elements 应该是 0,而不是 size。而vec-&gt;size 应该是size,而不是 size*2。所以正确的函数应该是

// remove the const, you are modifying the data vec is pointing to
int initVector(Vector vec, size_t size)
{
    if(vec == NULL)
        return 0;

    vec->vec = calloc(size, sizeof *vec->vec);
    if(vec->vec == NULL)
        return 0;

    vec->elements = 0;
    vec->size = size;
    return 1;
}

现在insertVector 只会分配新空间,当所有分配的空间 被使用了。

我建议你使用memmove来复制内存:

// again, remove the const here
int insertVector(Vector vec, const size_t pos, const item a)
{
    if(vec == NULL)
        return 0;

    if(vec->elements==vec->size)
    {
        item* temp=realloc(vec->vec,(vec->size*2)*sizeof *temp);
        if(temp==NULL)
        {
            fprintf(stderr, "Error: space unavailable\n");
            return 0;
        }

        vec->vec=temp;
        vec->size*=2;
    }

    // I use vec->elements as upper limit,
    // otherwise you could have "holes" in the array and
    // you wouldn't realize it.
    if(pos < 0 || pos > vec->elements)
    {
        fprintf(stderr, "invalid position\n");
        return 0;
    }

    memmove(vec->vec + pos + 1, vec->vec + pos, (vec->elements - pos) * sizeof *vec->vec);

    vec->vec[pos] = a;
    vec->elements += 1;

    printf("size is %lu\nelements are %lu\n",vec->size,vec->elements);

    return 1;
}

【讨论】:

  • 现在我想起来了,我不明白为什么它仍然可以与 const...
  • @Adonai 我现在意识到,这是因为typedef,const 适用于指针。如果你做了vec = malloc(sizeof *vec),那么你会得到这个错误:error: assignment of read-only parameter vec。如果您将insertVector 声明为int insertVector(const struct _vector *vec, ...),那么您将收到一条错误消息,告诉您无法更改内容。
【解决方案2】:

在您的initVector 函数中,您错误地设置了大小,将其设置为您使用calloc 分配的大小的两倍。然后,当您添加新元素时,此内存将被覆盖,这就是您最终调用 realloc 时 free 失败的原因。将initVector 更改为:

void initVector(const Vector vec,const size_t size) 
{
    vec->vec=calloc(size,sizeof(item));
    vec->elements=size;
    vec->size=size;
}

【讨论】:

  • 是的,我设法看到了,我将 size*2 放在 calloc 中,现在它可以工作了。
  • 我还是觉得vec-&gt;elements应该初始化为0,因为你只分配了空间,没有分配任何item,所以你有0个元素。
  • 它实际上不会引起问题,因为一旦向量被初始化,我使用元素作为我填充向量的 for 循环的上限......但这仅用于测试目的否则我应该一个一个地放置元素。
猜你喜欢
  • 2015-06-28
  • 2016-06-25
  • 2012-03-05
  • 2018-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多