开发者

Pointer and allocation outside function or static variable and allocation inside?

Don't freak out about the length of my post, it's pretty simple, I just don't know how to put it any shorter:

I have two ways of doing something pretty much similar to merging two arrays via a function. Here I call the function combine_data(). The arrays are called data1 and data2. Suppose my arrays are like:

int num1 = 4;
int num2 = 6;

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

Solution 1

I can either use a solution I find more elegant but I'm unsure if it's good practice and will behave properly. The solution relies on a static variable intended to make the array persistent. Somehow that feels like it could blow up in my face some way.

// 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() ???

Solution 2

Or I could use the approach I'm more used to, that uses pointers for the same functionality:

// 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);

Solution 2 has the problem that nothing prevents the user from this: combine_data(num1, data1, num2, data2, data1), which would screw up data1. Solution 2 hides the allocation, and is easier to use, which I find more elegant, but I don't know how it will behave especially when freeing the memory. Which solution is the best and why?

Also btw. is there a difference between the two?:

const int* const name
const int const *name

Edit: One really is a syntax error i've seen in faulty code and wondered. Also discarded the static.


Why would you need to make combi static in solution 1? The pointer does not have to persist, only what is pointed to by it. The pointer is then returned by value, so no memory leak occurs.

Which solution you choose depends solely on your assumption as to the style of the whole program. You have to decide whether the function should allocate and return a pointer to allocated memory, or accept a pointer to already allocated memory.

Both solutions are correct, and in my opinion equally good. In solution 2 you may also check for equality between input and output pointers and return an error code. You can even check for memory overlapping, not only pointer equality. But then again, it all depends on what responsibilities you assign to different parts of your program.


Your second solution is better. Static variables are going to kill you would you ever go multithreaded.

As of prventing the user from using your function wrong, you can assert that data1+num1 and data2+num2 don't overlap.

There is a difference between const int* const name and const int* name. The latter means you can't change the values pointed by name but you can assign name itself to another pointer, the former means you can't change the values nor the pointer.


is there a difference between const int* const name and const int const *name

Yes, the second is a syntax error.

As to which of the solutions is better... Well, I don't think that the problem that you're afraid in solution 2 isn't present in solution 1. You do return combi in the first solution, so the user can save it and then pass it again to the same function which would screw things up as well. So, my vote goes for second solution. (by the way, you could check in the function that neither data1 nor data2 are equal to combi)


The second solution has the advantage that you can pass it arrays of different storage classes. Global array, stack allocated (VLA) or heap allocated. This gives you more flexibility which might come handy if your function is used by different parts of a big project (imagine a library).

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

EDIT: Besides, the advantage of making the allocation in the caller instead of the callee can have also impact on the algorithmic complexity of the solution. If we imagine that your combine function is called in a loop. With the first solution you will have a lot of copies.

1st solution

 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); 

2nd solution

 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); 


The static in the first solution serves no purpose, you can remove it and the function will function identical (except that it is threadsafe).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜