假设函数
void foo(int n, double x[])
对n-vector x
进行排序,对x
执行一些操作,然后在返回之前将原始排序恢复为x
。所以在内部,foo
需要一些临时存储,例如,至少一个n向量的整数,以便它存储原始排序。
处理此临时存储的最佳方法是什么?我可以想到两个明显的方法:
foo通过声明一个内部数组声明自己的工作区,即在foo
的顶部我们有
int temp[n];
在主调用例程中,动态分配int的n向量,并在每次调用时将存储传递给foo
版本,该版本接受临时存储作为第3个arg,即
double *temp = malloc(n*sizeof(double));
foo(n, x, temp);
我担心选项1效率低下(函数foo
将被称为许多次使用相同的n
),而选项2只是简单的丑陋,因为我必须随身携带这个临时存储空间,以便在我恰好需要拨打foo(n,x)
时随时可用。
还有其他更优雅的选择吗?
答案 0 :(得分:5)
选项1显然是最干净的(因为它是完全封装的)。因此,请使用选项1,直到分析确定这是一个瓶颈。
<强>更新强>
@ R的评论如下是正确的;如果n
很大,这可能会导致您的筹码量减少。前C99“封装”方法将malloc本地数组,而不是将其放在堆栈上。
答案 1 :(得分:5)
如果你最终使用选项2 - 也就是说,该函数使用在别处分配的内存 - 使用适当的封装。
简而言之,不要传入原始数组,传入一个context
对象,该对象具有匹配的init
和release
函数。
然后,用户仍然必须传递上下文并正确设置并将其拆除,但细节对她隐藏,并且她不关心分配的细节。这是C中的常见模式。
typedef struct {
double* storage;
} foo_context;
void foo_context_init(foo_context*, int n);
void foo_context_free(foo_context*);
void foo(foo_context* context, int n, double x[]);
现在,对于一个非常简单的案例,这显然是一个巨大的开销,我同意Oli的选择1要求。
答案 2 :(得分:4)
在大多数体系结构中,选项1非常有效,因为它在堆栈上分配内存,通常是堆栈和/或帧指针的添加。小心不要让n太大。
答案 3 :(得分:3)
正如Oli在他的回答中所说,最好的办法是让这个临时数组具有自治功能。除非在非常快的循环中调用该函数,否则单个分配不会花费太多...所以先将其弄好,然后分析然后确定是否值得进行优化。
那说在分析后的几个案例中,当所需的临时数据结构比单个int数组更复杂时,我采用了以下方法:
void foo(int n, ... other parameters ...)
{
static int *temp_array, temp_array_size;
if (n > temp_array_size)
{
/* The temp array we have is not big enough, increase it */
temp_array = realloc(temp_array, n*sizeof(int));
if (!temp_array) abort("Out of memory");
temp_array_size = n;
}
... use temp_array ...
}
请注意,使用静态数组排除例如多线程或递归,这应该在文档中明确说明。