【问题标题】:Reallocating 1D array of integers, keeping original values, zeroing out rest重新分配一维整数数组,保持原始值,将剩余部分归零
【发布时间】:2019-04-04 21:34:01
【问题描述】:

我想调整一维整数数组的大小,保留原始数组中的值并用零初始化新值。到目前为止,我已经提出了两种选择(a)使用callocmemcpy

// Resizes composition
int compo_resize(int len, int *a) {

    // initialise new composition
    int *c = calloc(2*len, sizeof a[0]);

    if (c == NULL) {
        fprintf(stderr, "calloc() failed");
        return LieanderErrorOutOfMemory;
    }

    // copy numbers from old to new composition
    memcpy(c, a, sizeof a[0] * len);

    // modify composition in-place
    *a = *c;

    // release memory
    free(c);

    return LieanderSuccess;
}

和 (b) 使用 reallocmemset

// Resizes composition
int compo_resize(int len, int *a) {

    printf("Note: resizing composition...\n");

    // reallocate memory
    void *c = realloc(a, 2*len);

    if (c == NULL) {
        fprintf(stderr, "realloc() failed");
        return LieanderErrorOutOfMemory;
    }
    else {
        // reassign pointer
        a = c;

        // zero out new elements
        memset(&a[len], 0, len * sizeof a[len]);
    }

    return LieanderSuccess;
}

我想说第二种方法更优雅、更快。但是,当集成到更大的程序中时,代码开始返回意外的错误值。我在方法(b)中做错了吗?我错过了什么明显的东西吗?

combo_resize() 的调用是int retval = compo_resize(f->len, f->a),其中f 是一个称为pair 的自定义结构:

typedef struct {
    int  fac;  // multiplication factor
    int  idx;  // index of Lieander
    int  len;  // length of compositions
    int  kth;  // no. of elements in compositions
    int *a;    // composition 1
    int *b;    // composition 2
    int  num;  // natural no.
} pair;

【问题讨论】:

  • 你能更具体地定义“意外的、不正确的值”吗?您在该函数中使用void* 表示临时int* 也很奇怪。只需使用正确的类型即可避免歧义。听起来你在这里有很多未定义的行为是由于在free 之后使用指针等等造成的。
  • 第二个,realloc(a, 2*len); 是错误的。应该是realloc(a, 2 * len * sizeof *a); 你记得memset 中的sizeof 乘数;您在分配中遗漏了它的任何特殊原因?无关,memset 可以简单地使用a+len 作为目标。而且我希望 调用者 以某种方式知道新容量是什么,因为没有从该函数返回给他们的相同功能。
  • 您将立即释放新创建的阵列。而*a = *c;的意图根本就不清楚。
  • @mabalenk 请edit 您的问题并在那里进行说明。还告诉我们f->a 到底是什么。但也许你应该使用下面的赞成答案之一并像这样调用函数:compo_resize(f->len, &f->a)
  • mabalenk,为什么 2*realloc(a, 2*len)?我希望有像 compo_resize(int *a, int oldsize, int newsize) 这样的签名。

标签: c memcpy realloc calloc memset


【解决方案1】:

首先,你需要传递你要更新的指针的地址,否则指针不会在函数外被修改。因为如果 realloc 找不到足够长的连续区域,它可能会更改数据的位置。

其次,确保您严格控制数组的大小与字节大小。

// Resizes composition
int compo_resize(int len, int **a) {

    printf("Note: resizing composition...\n");

    // reallocate memory
    void *c = realloc(*a, sizeof(int) * 2 * len);

    if (c == NULL) {
        fprintf(stderr, "realloc() failed");
        return LieanderErrorOutOfMemory;
    }
    else {
        // reassign pointer
        *a = c;

        // zero out new elements
        memset(&c[len], 0, sizeof(int) * len);
    }

    return LieanderSuccess;
}

【讨论】:

  • 请注意,2 * len * sizeof(int) 可以在 sizeof(int) * 2 * len 没有溢出的情况下溢出:(len > INT_MAX/2)。推荐第二个。
【解决方案2】:

int *a 参数需要替换为int **a,因为您要代表调用者更改指针。

// Resizes composition
int compo_resize(int len, int **a) {

    printf("Note: resizing composition...\n");

    // reallocate memory
    int *c = realloc(*a, sizeof(c[0])*2*len);

    if (c == NULL) {
        fprintf(stderr, "realloc() failed");
        return LieanderErrorOutOfMemory;
    }
    else {
        // reassign pointer
        *a = c;

        // zero out new elements
        memset(&c[len], 0, len * sizeof c[len]);
    }

    return LieanderSuccess;
}

【讨论】:

  • 请注意,2*len*sizeof(c[0]) 可以在 sizeof(c[0]) * 2 * len 不溢出时溢出案例:(len > INT_MAX/2)。推荐第二个。
  • @chux 好点。我根据您的建议重新排列了表达式。使用size_t len 而不是int len 会更好,但我希望尽可能接近OP 的原版。
  • @IanAbbott,我已根据您的建议更改了代码。它可以编译,但我在程序执行结束时获得了意外的不正确值。数组a 包含整数,这些整数会被减少和抵消,直到达到某个组合。最后总结出很多pairs的组合。现在,这个总和有时会有所不同。这是错误的和出乎意料的。
  • @mabalenk 问题出在您未发布的代码中。发布minimal reproducible example
  • @mabalenk 我希望你意识到你现在需要调用像retval = compo_resize(f->len, &f->a); 这样的函数(注意& 添加到第二个参数)。
【解决方案3】:

1- 不要释放所有涂层内存,因为您将在函数返回后使用它。

2- 将旧的 *a 复制到 *c 后考虑释放它。

3- 更改函数声明:

int compo_resize(int len, int *a);

int compo_resize(int len, int **a);

因为你想更新指针本身的值以指向一个新创建的数组。

【讨论】:

  • 如 man(3) realloc 中所述:if the area pointed to was moved, a free(ptr) is done.
  • @Tezrig,我不明白你的意思,提出问题的用户在第一种方法中没有提到任何 realloc。你只是假设我正在处理他的第二次审判!
猜你喜欢
  • 2012-01-28
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
相关资源
最近更新 更多