功能需要自己的工作空间阵列 - 最佳实践?

时间:2011-07-03 13:49:48

标签: c

假设函数

void foo(int n, double x[])

对n-vector x进行排序,对x执行一些操作,然后在返回之前将原始排序恢复为x。所以在内部,foo需要一些临时存储,例如,至少一个n向量的整数,以便它存储原始排序。

处理此临时存储的最佳方法是什么?我可以想到两个明显的方法:

  1. foo通过声明一个内部数组声明自己的工作区,即在foo的顶部我们有

    int temp[n];
    
  2. 在主调用例程中,动态分配int的n向量,并在每次调用时将存储传递给foo版本,该版本接受临时存储作为第3个arg,即

    double *temp = malloc(n*sizeof(double));
    foo(n, x, temp);
    
  3. 我担心选项1效率低下(函数foo将被称为许多次使用相同的n),而选项2只是简单的丑陋,因为我必须随身携带这个临时存储空间,以便在我恰好需要拨打foo(n,x)时随时可用。

    还有其他更优雅的选择吗?

4 个答案:

答案 0 :(得分:5)

选项1显然是最干净的(因为它是完全封装的)。因此,请使用选项1,直到分析确定这是一个瓶颈。

<强>更新

@ R的评论如下是正确的;如果n很大,这可能会导致您的筹码量减少。前C99“封装”方法将malloc本地数组,而不是将其放在堆栈上。

答案 1 :(得分:5)

如果你最终使用选项2 - 也就是说,该函数使用在别处分配的内存 - 使用适当的封装。

简而言之,不要传入原始数组,传入一个context对象,该对象具有匹配的initrelease函数。

然后,用户仍然必须传递上下文并正确设置并将其拆除,但细节对她隐藏,并且她不关心分配的细节。这是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 ...
}

请注意,使用静态数组排除例如多线程或递归,这应该在文档中明确说明。