【问题标题】:How allocate or free only parts of an array?如何仅分配或释放数组的一部分?
【发布时间】:2010-03-19 18:41:15
【问题描述】:

看这个例子:

int *array = malloc (10 * sizeof(int))

有没有办法只释放前 3 个块?

或者有一个带有负索引的数组,或者不以 0 开头的索引?

【问题讨论】:

    标签: c arrays


    【解决方案1】:

    您不能直接释放前 3 个块。您可以通过重新分配更小的数组来做类似的事情:

    /* Shift array entries to the left 3 spaces. Note the use of memmove
     * and not memcpy since the areas overlap.
     */
    memmove(array, array + 3, 7);
    
    /* Reallocate memory. realloc will "probably" just shrink the previously
     * allocated memory block, but it's allowed to allocate a new block of
     * memory and free the old one if it so desires.
     */
    int *new_array = realloc(array, 7 * sizeof(int));
    
    if (new_array == NULL) {
        perror("realloc");
        exit(1);
    }
    
    /* Now array has only 7 items. */
    array = new_array;
    

    至于问题的第二部分,您可以增加 array 使其指向您的内存块的中间。然后您可以使用负索引:

    array += 3;
    int first_int = array[-3];
    
    /* When finished remember to decrement and free. */
    free(array - 3);
    

    同样的想法也适用于相反的方向。您可以从 array 中减去以使起始索引大于 0。但请注意:正如 @David Thornley 指出的那样,根据 ISO C 标准,这在技术上是无效的,并且可能不适用于所有平台。

    【讨论】:

    • 我会将你的第一句话修改为“你不能直接释放前 3 个块除非你单独分配每个块”。您可以分配(在此示例中)10 个单独的块并将指向这些块的指针存储在一个数组中(但不能保证这些块在物理上是连续的)。
    • 正如您在第一个答案中所说,当我重新分配数组并仅提供 7 个块时,我的数组将从哪个索引开始? 3 还是 0?如果第一个是正确的,如何在不为 0 1 n 2 索引分配内存的情况下从 3 索引开始我的数组?
    • 为什么要这样做?可能有更好的方法来做任何你想做的事情。更改数组的基本索引是一个不寻常的请求。
    • 您带有负索引的代码是正确的。如果您在数组边界之外生成了一个指针,那只会是不正确的。
    • 但是这个解决方案有使数组上的迭代器失效的风险,对吧?因为它可能会被完全移到另一个地方。
    【解决方案2】:

    你不能释放数组的一部分——你只能free()一个你从malloc()得到的指针,当你这样做时,你将释放你要求的所有分配。

    就负数或非基于零的索引而言,当您从malloc() 取回指针时,您可以对指针做任何您想做的事情。例如:

    int *array = malloc(10 * sizeof(int));
    array -= 2;
    

    创建一个具有有效索引 2-11 的数组。对于负指数:

    int *array = malloc(10 * sizeof(int));
    array += 10;
    

    现在您可以像array[-1]array[-4] 等一样访问这个数组。

    确保不要访问阵列外的内存。这种有趣的事情在 C 程序和 C 程序员中通常是不受欢迎的。

    【讨论】:

    • array -= 2; 是未定义的行为,IIRC,因为它形成了一个既不指向有效内存也不指向某个有效内存末尾的指针值。这通常不是现代计算机的问题,但有些系统(如旧的 Boehm 保守垃圾收集器)会遇到此问题。
    • +1 让我停下来思考——尽管我肯定也皱着眉头。
    • @David - Boehm 保守的垃圾收集器有很多问题。任何使用它的人都会调整他们的习语以适应,但这并不意味着每个人都必须这样做。 GC 不是标准 C 语言的一部分。指针算术是 C 中的日常工作 - 当指针指向不存在的东西时取消引用指针是明显的未定义行为,但只是将超出范围的指针存储在某处?如果这是未定义的行为,我会感到非常惊讶。
    • @Steve,大卫说的是对的。指向分配的内存之外是未定义的,除了允许的末尾之外。您甚至不必取消引用指针。
    • @Steve314:有很多这样的“为什么这是未定义的行为?”问题,它可以帮助想象一个只有有效值可以加载到寄存器中的架构。该标准谈到“陷阱表示”,这意味着内存中的位模式,如果使用,会导致未定义的行为。您不再期望整数和指针如此,但您可能会期望浮点数。同样的原理激发了array-2 是未定义行为的想法——C 旨在允许在指针寄存器物理上无法保存无效指针的架构上实现。
    猜你喜欢
    • 2023-01-21
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    • 1970-01-01
    • 2020-03-08
    相关资源
    最近更新 更多