return 和释放 C 中动态分配的数组都可以吗?

Possible to both return and free a dynamically allocated array in C?

是否可以同时 return 和释放动态分配的数组?

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)

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

注意,毕竟,

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

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

此外,由于您可以拥有一份数据副本和许多指向它的指针,因此除了修改数据副本外,您通常不需要复制数据,而是制作一份仅供阅读的副本,没有必要,你只需要使用指针,如果你不想保留原始数据的副本,你也可以通过指针修改它而不是创建它的副本。

要正确调用 free,在返回数组的调用函数中调用 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); 非常具有误导性。

注意:你真的不需要写一个循环来复制内容,你可以使用string.h标准头中的memcpy() , 这将是 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;
}

上面我说“robust”是因为代码会检查 malloc() 的 return 值,失败时为 NULL

如果您试图在同一函数 中return 并释放一个动态分配的数组,那您就是自相矛盾了。堆(动态)分配的目的是创建一个在函数 returns 之后持续存在的对象。接收方有义务在不再需要时释放它。

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

如果您 return 数组,调用代码必须负责释放它(函数必须 而不是 释放它)。如果你不 return 数组,函数 必须 释放它,但是函数无论如何都没有意义。因此,函数不会释放数组。

如果您使用:

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);

这更不容易出错,更容易理解,并且使用的字符稍微少一些!

有时您需要提供自己的函数来释放您分配的内存...例如,在 Windows 上,当您调用 returns DLL 中的代码时分配给你的内存,你必须通过调用同一个 DLL 中的 free 来释放它,否则会发生内存泄漏(最好的情况,最坏的情况是堆损坏)......这是因为 MS windows 中的 DLL 有它们的彼此和主调用程序拥有单独的堆。

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

无论如何,要执行类似的操作,您将以这种方式对 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

Link 到相关的 MSDN 文章:http://msdn.microsoft.com/en-us/library/ms235460.aspx