【问题标题】:Why is it desirable to realloc() memory for a growing array of pointers?为什么需要为不断增长的指针数组重新分配内存?
【发布时间】:2017-10-03 07:58:20
【问题描述】:

typedef struct {
    void **head;
    size_t used_size;
    size_t free_size;
    size_t current_size;
    size_t size_increment;
} GrowingArray;

GrowingArray createEmptyGrowingArray(int initial_size, int size_increment) {
    GrowingArray empty_growing_array;
    empty_growing_array.head = malloc(initial_size * sizeof(void *));
    empty_growing_array.used_size = 0;
    empty_growing_array.free_size = initial_size;
    empty_growing_array.current_size = initial_size;
    empty_growing_array.size_increment = size_increment;

    return empty_growing_array;
}

GrowingArray appendToGrowingArray(GrowingArray growing_array, void *new_element) {

    void *new_head_of_array;

    if (growing_array.free_size == 0) {
        new_head_of_array = realloc(growing_array.head, (growing_array.current_size + growing_array.size_increment) * sizeof(void*));
        if (new_head_of_array == NULL) {
            printf("Reallocation failure.\n");
        }

        growing_array.free_size = growing_array.size_increment;
        growing_array.current_size += growing_array.size_increment;
        growing_array.head = new_head_of_array;
    }

    growing_array.head[growing_array.used_size++] = new_element;
    growing_array.free_size--;

    return growing_array;
}

void finalizeGrowingArrayMemory(GrowingArray growing_array) {
    growing_array.head = realloc(growing_array.head, growing_array.current_size * sizeof(void *));
}

void freeGrowingArray(GrowingArray growing_array) {
    free(growing_array.head);
}

int main(int argc, char* argv[]) {
    GrowingArray test_array = createEmptyGrowingArray(5, 1);

    int *test_integer = (int *)malloc(1 * sizeof(int));
    *test_integer = 4;

    int *another_integer = (int *)malloc(1 * sizeof(int));
    *another_integer = 6;

    int *yet_another_integer = (int *)malloc(sizeof(int));
    *yet_another_integer = 9;

    test_array = appendToGrowingArray(test_array, test_integer);
    test_array = appendToGrowingArray(test_array, another_integer);
    test_array = appendToGrowingArray(test_array, yet_another_integer);
    finalizeGrowingArrayMemory(test_array);

    printf("%x,", *(int *)test_array.head[0]);
    printf("%x,", *(int *)test_array.head[1]);
    printf("%x\n", *(int *)test_array.head[2]);

    freeGrowingArray(test_array);

    printf("Going to free %llx\n", (long long int)test_integer);
    free(test_integer);

    printf("Going to free %llx\n", (long long int)another_integer);
    free(another_integer);

    printf("Going to free %llx\n", (long long int)yet_another_integer);
    free(yet_another_integer);

    return 0;
}

我根据这个问题的正确答案中提供的示例代码编写了这段代码:How may I implement a generic, dynamically growing array in C?

提供的答案包括一个简单地重新分配指针数组的函数。预期的用途是在将几个项目附加到数组后调用它,如答案代码所示。

我想知道为什么要这样做。它提供什么好处? realloc() 是否会尝试根据之前的使用情况预测一块内存将如何使用,然后将其移动到它认为最好的位置?

谢谢!

作为附加是或否问题:我应该在createEmptyGrowingArray() 中使用calloc() 而不是malloc()

【问题讨论】:

  • 请注意,如果数组总是按 因子 扩展(即大小乘以 1.2、1.5 甚至 2),则单个元素的插入将摊销运行O(1) 的时间,即常数。如果你在上面的代码中使用常量增量,添加一个新元素的运行时间是O(n)!

标签: c arrays memory realloc


【解决方案1】:

我想知道为什么要这样做。它有什么好处?

我想你是在问为什么它有一个函数,或者为什么有一个可配置的增量:

  • 将重新分配的详细信息分隔到自己的区域中很方便,以避免使您的代码混乱,并提供可重复使用的调整大小操作,该操作可以从您可能实现的其他形式的“插入”调用中调用。
  • 具有增量配置允许您将数组扩大多个元素,从而防止过度重新分配。
  • 虽然您的示例没有这样做,但增加增量大小也很有用。这将允许 constant amortized time complexity 进行阵列增长。

realloc() 是否会尝试根据其先前的使用情况预测一块内存将如何使用,然后将其移动到它认为最好的位置?

不,它不知道你的块是做什么用的。它只是分配一块内存。如果它可以在不移动内存的情况下调整它的大小,它会的。但是如果没有足够的空间,或者它必须被移动到不同的分配方案(内存管理器经常根据它们的大小将块分成不同的区域),那么指针将移动并且该内存的内容将被复制到新的位置。

作为附加是或否问题:我应该在 createEmptyGrowingArray() 中使用 calloc() 而不是 malloc() 吗?

使用calloc 是合理的做法,但是当您创建一个空数组时,请记住您将当前大小设置为零,因此malloc 就足够了,因为您不会使用那些未初始化的值,直到您稍后(附加后)初始化它们。此外,在调用realloc 来增加块后,您当前没有将新内存中的指针归零,因此它不会提供与您的“创建”操作的概念奇偶性。

因此,在您的情况下,我建议使用malloc,这不会对您未使用的数据的状态产生不切实际的期望。如果你想在创建时使用calloc,那么你也应该使用memset来将增长后的新内存归零。

【讨论】:

  • 一些内存分配实现将大小四舍五入到某个块大小的倍数,因此 realloc 更有可能在不移动任何内容的情况下成功。
  • 没错。但在某些时候,它通常必须移动。
  • 我的评论解决了他关于 realloc 是否试图做出预测的问题。这是一种预测。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 2020-03-04
相关资源
最近更新 更多