【问题标题】:C dynamicaly changing size of array using malloc and memcpy [duplicate]C使用malloc和memcpy动态改变数组的大小[重复]
【发布时间】:2016-10-03 13:10:44
【问题描述】:

我想写一个函数来改变动态数组的大小并允许用户一次填充它。我知道我应该使用“realloc”来做到这一点(所以我这样做了,所以它起作用了......)但我的第一次尝试看起来像这样:

void ChangeDynamicArraySize(int* dArray, int oldSize, int newSize){

    int* tempArray = (int*) malloc(sizeof(int) * oldSize);
    CopyArray(tempArray, dArray, oldSize);
    free(dArray);
    dArray = (int*) malloc(sizeof(int) * newSize);
    CopyArray(dArray, tempArray, oldSize);

    for (int i = oldSize; i < newSize; i++){
        scanf("%i", &dArray[i]);
    }
    PrintArray(dArray, newSize);
    free(tempArray);
}

在函数体中“PrintArray(dArray, newSize);”工作正确。 但是当从 main() 调用时,它会给出如下结果: - 17891602 - 17891602 - 17891602 - 17891602

所以看起来 dArray 被释放了...?但据我所知,分配的内存不会在退出函数后自动释放。

那可能是什么原因呢?

【问题讨论】:

  • A,而 CopyArray 只是我的 memcpy() 版本
  • dArray 是按值传递的,您只是更改其本地副本。

标签: c malloc dynamic-memory-allocation memcpy realloc


【解决方案1】:

在 C 中,函数参数在本地复制。您对指向 (*dArray) 的值 dArray 所做的任何更改都有效,但您对作为参数传递的 dArray 的(地址)所做的任何更改都仅适用于此函数,因为它是复制。

您可能希望传递数组的地址(主函数中的 &amp;array,函数原型中的 dArray**)并改为更改指针。

类似这样的:

void ChangeDynamicArraySize(int** dArray, int oldSize, int newSize){

    int* tempArray = (int*) malloc(sizeof(int) * oldSize);
    CopyArray(tempArray, *dArray, oldSize);
    free(*dArray);
    *dArray = (int*) malloc(sizeof(int) * newSize);
    CopyArray(*dArray, tempArray, oldSize);

    for (int i = oldSize; i < newSize; i++){
        scanf("%i", dArray[i]);
    }
    PrintArray(*dArray, newSize);
    free(tempArray);
}

或者,您也可以只返回新的 malloced 数组的地址(让您的函数返回此 int* 而不是无值)。

此外,为了获得良好的实践,您可能需要not cast the return of malloc,并检查它是否失败和changed ERRNO(如果您使用 POSIX API)。

【讨论】:

  • A,好的...我明白了,谢谢 :)
  • 我试过了,但是 scanf("%i", dArray[i]) 出现访问冲突写入位置 0xcccccccc。
  • 但是那个:scanf("%i", &(*dArray)[i]) 似乎没问题 ;) 现在它正在工作。
  • @Diti——请看我回答的结尾。我认为您的解决方案存在进一步的混淆,但如果我遗漏了什么,请纠正我:您有*dArray = malloc(sizeof(int) * newsize)),它分配了足够的内存来存储newsizeints,但是指向该内存第一个地址的指针认为它指向的位置包含int地址
  • @Diti——道歉——我明白你现在在做什么。我一直遇到问题,因为free(*dArray) 试图在我的示例代码中释放一段堆栈分配的内存,因为我从main() 中的一个数组开始而不是malloc 占用一些空间。我将在下面更新我的答案。
【解决方案2】:

在函数内部,您将 malloc 分配的新内存分配给具有块范围的dArray。您需要将此指针传递回调用函数。 dArray 是你传入的指针的副本,当你返回调用函数时,原来的指针不变。你应该有一个像这样的函数调用:

ptr = ChangeDynamicArraySize(ptr, oldSize, newSize);

由于dArray 是函数调用中传递的指针的副本,因此当您更改*dArray 的值时,该值在函数外部可见,因为您正在更改存储在指向的内存位置的值原始指针和副本。但是当你在函数内重新分配dArray 指针时,你只是说这个指针现在应该指向其他位置。原来的仍然指向原来的位置。

原始问题中的解决方案存在一个基本问题:当您将指向内存部分的指针传递给函数时,该指针使用 malloc()calloc()realloc() 重新分配该内存,新的内存有一个新地址。即使使用realloc() 也是如此,因为旧位置可能没有足够的连续字节来分配请求的内存。原始解决方案在ChangeDynamicArraySize() 函数内部重新分配内存,然后修改此内存的内容。但是返回后,调用函数不知道新内存在哪里。所以,你必须将一个指向新分配内存的指针返回给调用者。

@Diti 提出了另一种解决方案,通过将指针的地址传递给数组的第一个元素来解决这个问题。这个指针可以被取消引用并给出新分配的内存地址的值。这样一来,调用函数就更明智了,因为每当调用函数访问数组时,它都是通过提供数组第一个元素的地址的指针来访问的。整洁的。但我仍然认为我更喜欢尽可能明确地传递指针——这对我来说似乎更清楚。

【讨论】:

  • 嗯,dArray 是一个指针,所以我认为在块中完成的操作也会影响它外部的指针——比如改变变量的值......
  • 不。在函数内部,您只是在使用副本。如果您在函数中更改*dArray,那将在函数外部可见,因为您正在更改存储在原始指针和副本指向的内存中的值。但是如果你在函数内部重新分配指针,你只是说这个指针,它是其他指针的副本,现在应该指向其他地方。
  • 好的,现在我明白了,如果我在我的 ChangeSize 函数体中调用 realloc(),那么效果在 main() 中也是可见的,因为 realloc() 指的是同时指向的内存块通过我的 MainPointer 和 ChangeSizePointer...希望我是对的...它只是改变它的大小,而不是位置。
  • 当然,但是realloc() 确实返回了一个指向 void 的指针,所以如果你不这样做,你会得到编译器警告(这不会阻止代码编译,但你应该尝试修复这些) t 用这个值做某事。我总是返回指针,以便我可以明确地看到调用函数中的指针已被重新分配。
  • 废话,我不知道我在想什么——当内存重新分配时,比如说,dArray,不能保证新内存与旧记忆!因此,您确实必须将新位置传递回调用函数。我用一个小数组(5 个元素)做了一个玩具例子,没有返回新地址,它工作了——但是有一个 4 字节的内存泄漏。底线:返回新地址!
猜你喜欢
  • 2012-04-17
  • 1970-01-01
  • 2015-06-06
  • 2017-03-08
  • 1970-01-01
  • 1970-01-01
  • 2014-12-26
  • 2023-04-07
  • 1970-01-01
相关资源
最近更新 更多