指针和分配在函数或静态变量和内部分配?

时间:2011-08-16 13:38:43

标签: c pointers static

不要对我的帖子长度感到不满,这很简单,我只是不知道如何把它缩短:

我有两种方法可以做一些非常类似于通过函数合并两个数组的方法。我在这里调用函数combine_data()。这些数组称为data1data2。假设我的数组如下:

int num1 = 4;
int num2 = 6;

double data1[num1] = /* some values */
double data2[mum2] = /* some values */

解决方案1 ​​

我可以使用我发现更优雅的解决方案,但我不确定这是不是很好的做法并且行为正常。 该解决方案依赖于一个旨在使数组持久化的静态变量。不知何故,感觉它可能会在某种程度上在我的脸上爆炸。

// SOLUTION 1
double* combine_data(
    const int num1, const double* const data1,
    const int num2, const double* const data2
) {
    int i;
    int num = num1 + num2;
    double *combi;   // static because the data stored the should persist
    combi = (double*)malloc( num*sizeof(*combi) );
    /* some code */
    for(i=0; i<num1; ++i)   combi[i] = data[i];
    for(i=num1; i<num; ++i) combi[i] = data[i];

    return combi;
}

double *combi = combine_data(num1, data1, num2, data2);
/* some code */
free(combi);    // problem with free of a static variable in combine_data() ???

解决方案2

或者我可以使用我更习惯的方法,它使用指针来实现相同的功能:

// SOLUTION 2
void combine_data(
    const int num1, const double* const data1,
    const int num2, const double* const data2
    double* combi
) {
    /* some code */
    for(i=0; i<num1; ++i)   combi[i] = data[i];
    for(i=num1; i<num; ++i) combi[i] = data[i];
}

int num = num1 + num2;
double *combi = (double*)malloc( num*sizeof(combi) );
combine_data(num1, data1, num2, data2, combi);
/* some code */
free(combi);

解决方案2存在的问题是,没有任何内容可以阻止用户:combine_data(num1, data1, num2, data2, data1),这会搞砸data1。解决方案2隐藏了分配,并且更容易使用,我发现它更优雅,但我不知道它在释放内存时会如何表现。 哪种解决方案最好?为什么?

还顺便说一下。两者之间有区别吗?:

const int* const name
const int const *name

编辑:一个确实是我在错误的代码中看到的语法错误并且想知道。也放弃了static

5 个答案:

答案 0 :(得分:3)

为什么需要在解决方案1中使combi静态?指针不必持久化,只需要指向它。然后按值返回指针,因此不会发生内存泄漏。

您选择哪种解决方案完全取决于您对整个计划风格的假设。您必须决定函数是否应该分配并返回指向已分配内存的指针,或者接受指向已分配内存的指针。

两种解决方案都是正确的,在我看来同样好。在解决方案2中,您还可以检查输入和输出指针之间的相等性并返回错误代码。您甚至可以检查内存重叠,而不仅仅是指针相等。但话说回来,这一切都取决于你为程序的不同部分分配的职责。

答案 1 :(得分:1)

你的第二个解决方案更好。如果你去多线程,静态变量会杀了你。

在防止用户使用您的函数时,您可以断言data1+num1data2+num2不重叠。

const int* const nameconst int* name之间存在差异。后者意味着您无法更改name指向的值,但您可以将name本身分配给另一个指针,前者意味着您无法更改值或指针。

答案 2 :(得分:1)

  

const int * const name和const int之间有区别吗?   const * name

是的,第二个是语法错误。

关于哪种解决方案更好......嗯,我不认为你在解决方案2中害怕的问题不在解决方案1中。你返回在第一个解决方案中combi,因此用户可以保存它,然后再将其传递给同样的函数,该函数也会。所以,我的投票是第二个解决方案。 (顺便说一句,你可以检查data1data2都不等于combi的函数

答案 3 :(得分:1)

第二种解决方案的优点是可以传递不同存储类的数组。全局数组,堆栈分配(VLA)或堆分配。这为您提供了更大的灵活性,如果您的函数被大项目的不同部分使用(想象一个库),这可能会很方便。

double combi[num1+num2];
combine_data(num1, data1, num2, data2, combi);
/* some code */
/*forget free(combi) it's not necessary anymore;

编辑:此外,在调用者而不是被调用者中进行分配的优点也会对解决方案的算法复杂性产生影响。如果我们想象你的组合函数是在循环中调用的。使用第一个解决方案,您将获得大量副本。

第一个解决方案

 data1, data2, data3, data4
 comb1 = combine_data(len1, data1, len2, data2);
 comb2 = combine_data(len3, data3, len4, data4);
 comb3 = combine_data(len1+len2, comb1, len3+len4, comb2);
 /* ... */
 free(comb1); 
 free(comb2); 
 free(comb3); 

第二个解决方案

 data1, data2, data3, data4
 comb = malloc(len1+len2+len3+len4);
 combine_data(len1, data1, len2, data2, comb);
 combine_data(len3, data3, len4, data2, comb+len1+len2);     /* This case can of course only be used because we know what combine does */

 /* ... */
 free(comb); 

答案 4 :(得分:0)

第一个解决方案中的static没有任何意义,您可以删除它,并且该函数的功能相同(除了它是线程安全的)。