可以在C中返回并释放动态分配的数组吗?

时间:2015-03-09 15:07:08

标签: c function malloc dynamic-arrays

是否可以返回并释放动态分配的数组?

int *mycopy(int *from, int len)
{
    int i;
    int *to;

    to = malloc(len*sizeof(int));

    for(i = 0; i < len; ++i) {
        to[i] = from[i]
    }

    return to;

    // how do I free the "to" array?
    // do i even need to, or does the array only have function scope
    // and get deleted when the function exits?
}

或者是

void mycopy(int *from, int *to, int len);

我唯一的选择?

mycopy函数只是一个简单的例子,但在实际代码中我想嵌套它们,比如调用它

a = mycopy(mycopy(b, 5), 5)

每次调用函数时如何在不分配更多内存的情况下执行此操作?感谢。

4 个答案:

答案 0 :(得分:6)

如果返回数组,则调用代码必须负责释放它(并且该函数必须释放它)。如果你没有返回数组,函数必须释放它,但无论如何这个函数都是没有意义的。因此,该函数不会释放数组。

如果您使用:

void mycopy(int *from, int *to, int len);

调用代码必须进行内存分配。如果您使用:

void mycopy(int *from, int **to, int len);

该函数可以进行分配 - 但它仍然不能释放它。

但最初的功能更好:写得很好。你可以这样称呼它:

int b[] = { 1, 2, 3, 9, 2 };
int *a = mycopy(b, sizeof(b)/sizeof(b[0]));
...use a...
free(a);

顺便说一句,您无法承担对您的复制功能的嵌入 - 或者,至少,您无法承担使用此功能的费用:

a = mycopy(mycopy(b, 5), 5);

它可能会泄漏内存。如果你必须进行嵌套调用(为什么?),那么你需要:

int *c;
int *a = mycopy((c = mycopy(b, 5)), 5);

但是写作会更干净,更整洁:

int *a = mycopy(b, 5);
int *c = mycopy(b, 5);

这不容易出错,更容易理解,并且使用稍少的字符来启动!

答案 1 :(得分:5)

如果您尝试在同一个函数中返回并释放动态分配的数组,那么您自相矛盾。堆(动态)分配的目的是创建一个在函数返回后持久存在的对象。接收者有义务在不再需要时将其释放。

现在,在您的嵌套示例中,内部mycopy(b, 5)引用被泄露;你不是把它放在一个持久变量中。我不知道为什么它如此重要。但是讨论很有意思,所以假设你坚持嵌套:为了避免内存泄漏,请使其成为原始数组的副本free() d 之后副本已完成,因此只有副本存活。有趣!但是现在,除了浪费时间之外,代码仍然没有做任何事情。这让我们回过头来说:也许这是占位符代码。您可能正在尝试做一些有用的事情,但这里没有足够的信息来采取适当的更高级别视图并重新执行整个策略。

答案 2 :(得分:1)

请注意,毕竟

a = mycopy(mycopy(b, 5), 5);

没有意义,因为丢失的副本,即你永远无法free()的副本不仅丢失了,而且是{{1}指向的原始数据的无用副本所以这对于没有指针的另一种语言来说可能没问题,但在c中它只是没有意义。

此外,既然你可以拥有一个数据副本和许多指向它的指针,你通常不需要复制数据,除了修改它的副本,但是只为了只读而复制数据必要的,你只需使用指针,如果你不想保留原始数据的副本,你也可以通过指针修改它而不是创建它的副本。

要正确调用free,在调用函数中数组为returend,当你确定不再需要访问数组时调用b,例如

free(array)

按照你想要的方式去做,即

int *x = mycopy(b, 5);
if (x == NULL)
    pleaseDoSomething_DoNot_Dereference_x();
int *a = mycopy(x, 5);
if (a == NULL)
    pleaseDoSomething_DoNot_Dereference_a();
free(x);
/* Do wahtever you want with a */
free(a);

是可能但不正确的,因为你会导致内存泄漏,并且没有办法像这样做,而且从长远来看你会学到一件好事,你做不到的事实这样做是有益的,因为这种语法a = mycopy(mycopy(b, 5), 5); 非常容易引起误解。

注意:您实际上不需要编写循环来复制内容,您只需使用a = mycopy(mycopy(b, 5), 5);标准标题中的memcpy(),这将是一个string.h函数的健壮版本

mycopy()

上面我说“健壮”因为代码会检查失败时int *mycopy(int *from, size_t length) { int *to; to = malloc(length * sizeof(*to)); if (to == NULL) return NULL; memcpy(to, from, length); return to; } 的{​​{1}}的返回值。

答案 3 :(得分:1)

有时您需要提供自己的功能来释放已分配的内存...例如,在Windows上,当您调用DLL中的代码并返回已分配的内存时,您必须释放它调用同一DLL内的free,否则会出现内存泄漏(最好的情况,最坏情况下堆损坏)......这是因为MS窗口中的DLL彼此之间以及主调用程序都有各自独立的堆。 / p>

这并不总是坏事,因为最常见的情况是分配的结构,其中包含指向其他已分配事物的指针,因此您可能需要一个例程来正确地释放它。

无论如何,为了做类似的事情,你会以这种方式编写myfree()例程(我编码的方式与上面的代码匹配):

void myfree( int** tofree )
{
  if( tofree != NULL ) {
    free( *tofree );
    *tofree = NULL;
  }
}

您可以通过以下方式调用您的函数和此函数:

int *x = mycopy(b, 5);
// then do some things with x, and after:
myfree(&x);
// x is freed, and set to =NULL

指向相关MSDN文章的链接:http://msdn.microsoft.com/en-us/library/ms235460.aspx