可以在被调用函数中malloc数组,但在调用函数中释放它吗?
我不是C方面的专家,但我想做的是:可以在被调用函数中malloc数组,但在调用函数中释放它吗?,c,C,我不是C方面的专家,但我想做的是: int main(void) { double *myArray; ... myFunction(myArray); ... /* save myArray contents to file */ ... free(myArray); ... return 0; } int myFunction(double *myArray) { int len=0; ...
int main(void) {
double *myArray;
...
myFunction(myArray);
...
/* save myArray contents to file */
...
free(myArray);
...
return 0;
}
int myFunction(double *myArray) {
int len=0;
...
/* compute len */
...
myArray = malloc( sizeof(double) * len );
if (myArray == NULL)
exit(1);
...
/* populate myArray */
...
return 0;
}
我想将myArray
的内容保存在main
内部,但在程序位于myFunction
内部之前,我不知道所需的大小
因为我使用的是CentOS 6.2 Linux,我只能找到一个gcc版本,最高版本为4.4.6(不支持C99声明可变长度数组的功能;请参阅中“可变长度数组”下的“断开”),我一直在使用
-std=c89
进行编译。由于myFunction
不会更改main中的值myArray
,它只会更改自己的副本,所以您所做的并不正确
除此之外,即使在风格上有争议也没关系。简单的答案是否定的
您没有传回指针
使用
编辑
poputateThis = *myArray;
/* populate poputateThis */
...
return 0;
编辑结束
poputateThis = *myArray;
/* populate poputateThis */
...
return 0;
编辑
poputateThis = *myArray;
/* populate poputateThis */
...
return 0;
应该简化你的工作
}作为良好设计和实践的问题(除了其他答案中指出的语法问题)只要符合您的代码库的最佳实践和透明性,这是可以的。您的函数应该被记录下来,以便调用方知道它必须自由,而且知道不分配它自己的内存。此外,考虑生成一个抽象数据类型,如:。
// myarray.h
struct myarray_t;
int myarray_init(myarray_t* array); //int for return code
int myarray_cleanup(myarray_t* array); // will clean up
myarray\u t
将保存一个动态指针,该指针将从调用函数中封装,尽管在init
和cleanup
函数中,它将分别分配和取消分配。您想做的很好,但您的代码没有这样做--main
永远看不到分配的内存myFunction
的参数myArray
使用函数调用中传递的值进行初始化,但此后修改它不会修改main
中同名的其他不相关变量
在您的代码片段中,似乎myFunction
总是返回0
。如果是这样,那么修复代码的最明显方法就是返回myArray
(并且不带任何参数)。然后main
中的调用看起来像myArray=myFunction();
如果myFunction
实际上已经使用了它的返回值,那么您可以传入一个指向double*
的指针,并将地址写入该指针的引用。Ed Heal的答案就是这样做的。double**
参数通常称为“out参数”,因为它是指向函数用于存储其输出的位置的指针。在这种情况下,输出是缓冲区的地址
另一种方法是这样做:
size_t myFunction(double *myArray, size_t buf_len) {
int len=0;
...
/* compute len */
...
if (buf_len < len) {
return len;
}
/* populate myArray */
...
return len;
}
size_t len = myFunction(NULL, 0);
// warning -- watch the case where len == 0, if that is possible
double *myArray = malloc(len * sizeof(*myArray));
if (!myArray) exit(1);
myFunction(myArray, len);
...
free(myArray);
您得到的是,调用者可以从任何方便的地方分配内存。您失去的是调用方必须编写更多的代码
有关如何使用该自由的示例,调用方可以编写:
#define SMALLSIZE 10;
void one_of_several_jobs() {
// doesn't usually require much space, occasionally does
double smallbuf[SMALLSIZE];
double *buf = 0;
size_t len = myFunction(smallbuf, SMALLSIZE);
if (len > SMALLSIZE) {
double *buf = malloc(len * sizeof(*buf));
if (!buf) {
puts("this job is too big, skipping it and moving to the next one");
return;
}
} else {
buf = smallbuf;
}
// use buf and len for something
...
if (buf != smallbuf) free(buf);
}
在只需要一个小缓冲区的常见情况下,避免使用
malloc
通常是一种不必要的优化——这只是调用者希望在内存分配方面有发言权的一个例子。一个更紧迫的原因可能是,您的函数被编译成与调用方函数不同的dll,可能是使用了不同的编译器,并且两者没有使用兼容的malloc/free
标题问题的答案是“是的,在许多库中它甚至是idomatic的”,但是您的实现被破坏了。是的,如果你做得对,没关系。是的,而且本质上这是malloc
的唯一目的。如果动态存储持续时间的生存期受相应的自动存储持续时间的限制,那么就根本没有理由使用动态存储持续时间。感谢您给出的明确答案。这会改变我在myFunction
中填充数组的方式吗?例如:For(i=0;i@ggkmath:是的,不过您可能会发现执行double*newArray=malloc(…)更方便
,使用newArray
以与当前使用myArray
相同的方式填充数组,然后编写*myArray=newArray;
。谢谢Steve,我相信*myArray=newArray
只是简单地调整指针,这样就只需要额外的8字节内存来完成您的注释(例如,我们暂时没有将len
的分配内存长度增加一倍,是吗)?我一直订阅使用malloc
(或new
)的东西,它应该负责免费
(或删除
)…如果数据在堆栈上或堆上,这种原理使我们可以使用相同的函数。@ggkmath:是的,*myArray=newArray
只是一个指针赋值。它对数组的内容没有任何作用。我想你是指myArray\u int(myArray\t**array)
看不到您将如何分配内存。不,ADT应该包装动态分配的数据。myarray\u t
本身将在堆栈上。哦,我明白了,那么您需要显示结构的定义以清楚地说明。@mux:myarray\u init
将执行类似于array->dataptr=malloc(…)
和myarray_cleanup
将执行类似免费(数组->数据ptr);
@SteveJessop是的,我现在知道了,谢谢,没有阅读完整答案,+1。