是否可以在C中返回和释放动态分配的数组?

是否可以在C中返回和释放动态分配的数组?,c,function,malloc,dynamic-arrays,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

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

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?
}
我唯一的选择

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

a = mycopy(mycopy(b, 5), 5)
如何在每次调用函数时都不分配更多内存的情况下执行此操作?谢谢。

请注意,毕竟

a = mycopy(mycopy(b, 5), 5);
没有意义,因为丢失的副本,即您永远无法
free()
的副本,不仅丢失了,而且是
b
指向的原始数据的无用副本,因此对于没有指针的另一种语言来说,这可能没什么问题,但在c语言中,这根本没有意义

此外,由于您可以拥有数据的一个副本和许多指向它的指针,因此通常不需要复制数据,只需修改副本,但不需要制作一个仅用于读取的副本,如果您不想保留原始数据的副本,您只需使用指针即可,您还可以通过指针修改它,而不是创建它的副本

要正确调用free,请在返回阵列的调用者函数中,在确定不再需要访问阵列时调用free(阵列)

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()
的返回值,失败时返回值为
NULL

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


现在,在嵌套示例中,内部
mycopy(b,5)
引用泄漏;您没有将其保存在持久变量中。我不知道为什么筑巢这么重要。但讨论起来很有趣,因此假设您坚持嵌套:为了避免内存泄漏,请使阵列的原始副本在复制完成后是
free()
d的副本,以便只有副本存活。有趣!但是现在,代码除了浪费时间外,什么都做不了。这让我们回到:也许这是占位符代码。您可能正在尝试执行一些有用的操作,但此处没有足够的信息来获取适当的更高级别视图并重新执行整个策略。

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

如果您使用:

void mycopy(int *from, int *to, int len);
void mycopy(int *from, int **to, int len);
调用代码必须进行内存分配。如果您使用:

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上,当您调用DLL中的代码并将分配的内存返回给您时,必须通过调用同一DLL中的空闲内存来释放代码,否则会出现内存泄漏(最佳情况,最坏情况是堆损坏)。。。这是因为MS windows中的DLL彼此之间以及主调用程序之间都有各自的堆

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

无论如何,要做到这一点,您需要以这种方式编写
myfree()
例程(我的编码方式与上面的代码相匹配):

您可以按以下方式调用函数和此函数:

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

链接到相关MSDN文章:

您想复制,然后复制副本,但让第二次复制销毁第一次复制?为什么?实际上,这与一份副本是一样的。你试图做的事情毫无意义,你想返回一些东西(我们可以猜测是为了使用它),同时又想删除它,因此,根据定义,要使它不可用,你能解释一下你想要做什么而不是你正在尝试做什么吗?那么我如何将数组释放到函数之外呢?释放返回的数组?在
a=mycopy(b,5)
示例中,只需在调用funtcion?@user1801359后释放a,您需要了解在
free()
之后,您不能再使用数据。在调用
free()
之前,使用数组是有效的,因此当不再需要该内存块时,需要调用
free()
。这允许程序员在程序的整个生命周期内使用相同的内存块;假设您调用
a=mycopy(b,5)
使用
空闲(a)释放分配的内存
。如果(to!=NULL)memcpy(to,from,length),则稍微整洁的是