2

In the C-programming language there are many different ways to declare the parameter of a function that takes an array as an argument passed through a pointer.

I have prepared an example that shows you what I mean. It is an implementation of the std::accumulate function in C++. It is a function that performes addition of all elements in an array and returns the result.

I can 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;
}

This can also be written to this (which means the exact same thing):

int accumulate(int n, 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;
}

All these options are very similar and generate the same executable code but they have a slight difference which is how the caller passes the arguments.

This is how the first two versions 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 thrid 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 third option requires to user to explicitly specify the address of a with &a. The first two options does not require this because arrays implicitly gets converted into pointers to the same type in C.

I have always preferred the third 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[] (and int *array) over int (*array)[] is that you get to write array[X] instead of (*array)[X] when you wish to grab an index.

But because I am not a professional I will ask you which version you prefer.

When do you use what? What are the reasons to choose one of these options over another?

I have mostly used int (*array)[N] but I see that the other two approaches are quite common as well.

2
  • I'm not yet happy with either answer. They neither of them mention pointer to array — which is the defining difference between int array[] (which is effectively int * in the context of a function argument list) and int (*array)[]. Commented Jan 13, 2015 at 6:41
  • @Jonathan If you (or someone else) have something to add you can make a new answer that I will accept if it is better. Maybe I accepted an answer to early this time which discourages new answers from showing up. When I look back at this question I also realize that it may be too "opinion based" for this Q&A site but go ahead and make a new answer if you think that the other answers are missing something. Commented Jan 13, 2015 at 8:57

2 Answers 2

4

When used as function parameters, int array[] and int *array are same. You can use either. It is matter of taste. int (*array)[] is tedious and not used widely.

int (*array)[n] is used most widely when 2D array is passed to a function. In that case you can access the element of array as array[i][j].

Sign up to request clarification or add additional context in comments.

2 Comments

Not really an answer. The first part of your answer is already stated in the question. And then, this question is not about 2D arrays ... and no, int accumulate(int n, int (*array)[]) is not sufficient to be able to use array[i][j]. For that, you have to put the n in: int (*array)[n].
@JensGustedt; Your point is valid. I made some correction. But, to me this question is primarily opinion based.
1

I also prefer the third variant, but it is not very commonly used. If so, with C99 I would write:

int accumulate(size_t n, int (*array)[n]) { ....

such that sizeof *array works in all cases inside the function.

4 Comments

Are you talking about two dimensional arrays? So sizeof knows the row length?
@haccks, no, the [*] is only for the prototype of the function, for the case that the names of the parameters aren't available. To really know sizeof *array the compiler has to see the real expression, and it is the one of the function definition that is evaluated.
@PaulOgilvie, no I am not talking about 2D arrays, here. This is one dialect to pass a pointer to a one dimensional array and to know the size of the array inside the function.
@JensGustedt; You are right. Its for prototype only.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.