samedi 10 janvier 2015

int * vs int (*)[N] in functions parameters taking arrays

When programming in C (or C++) there are two different ways to specify a parameter that is a pointer to an array in a function.


Here is an example (implementing std::accumulate from C++ in C).


I can write it like this:



int accumulate(int n, int *array) // or `int array[]`
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}


I can also write it like this:



int accumulate(int n, int (*array)[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += (*array)[i];
}
return sum;
}


Both versions are very similar and generate the same executable code but they have a slight difference.


This is how the first version gets called:



int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), a));
return 0;
}


This is how the second version gets called:



int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
return 0;
}


Note that the second version requires to user to explicitly specify the address of a with &a. The first version does not require this because arrays implicitly gets converted into pointers to the same type in C.


I have always preferred the second approach.


This is why:




  • It is more consistent with how other types are passed by pointers.



    int draw_point(struct point *p);

    int main()
    {
    struct point p = {3, 4};
    draw_point(&p); // Here is the 'address of' operator required.
    }



  • It makes it possible to use macros like ARRAY_LENGTH to get the amount of elements in the array.



    #include <stdio.h>
    #define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))

    void this_works(int (*array)[10])
    {
    /* This works! */
    printf("%d\n", ARRAY_LENGTH(*array));
    }

    void this_is_invalid_and_dangerous(int array[10])
    {
    /* This does NOT work because `array` is actually a pointer. */
    printf("%d\n", ARRAY_LENGTH(array));
    }



The only advantage I see with int array[] is that you get to write array[X] instead of (*array)[X] when you wish to grab an index.


What are your professional thoughts on this? Which approach do you think is better and why? Do you ever mix the two? If so when do you choose what?


Like I said have I always preferred using int (*array)[N] but I see that the int array[N] approach is used quite frequently as well.


Aucun commentaire:

Enregistrer un commentaire