arrayscpointers

C: passing an array of fixed size to function vs passing pointer?


in the man page for the pipe system call, I see

       /* On all other architectures */
       int pipe(int pipefd[2]);

       #define _GNU_SOURCE             /* See feature_test_macros(7) */
       #include <fcntl.h>              /* Obtain O_* constant definitions */
       #include <unistd.h>

       int pipe2(int pipefd[2], int flags);

the functions accept an array with a fixed size as their arguments int pipe(int pipefd[2]) but I know that in C you cannot pass an array as an argument because it decays to a pointer to the first element of the array. This question is mostly aimed at getting coding advice: I always use this signature: func(int *array, int len) whenever passing an array comes up in my programming, so I was wondering when would something like this be useful? The only use case I can think of is letting the user of the API know that you must pass an array sized for 2 elements (in this case), but from a quick compilation test, I can see that gcc does not complain when a mismatch occurs:

void func(int array[10])
{
}

int main(void)
{
    int array[4]; // passing int[4] but expected int[10]
    func(array);
    return 0;
}

gcc compiles the above code without errors or warnings. Any insight is welcome.


Solution

  • void func (int *array, int len) is pretty idiomatic C so using that style is never wrong. Mind "const correctness" however, in case the function doesn't modify the contents.

    You can use a fixed size array parameter if it makes sense to only ever accept such arrays. It is self-documenting code but as you noticed, it doesn't actually improve type safety since the array is adjusted to a pointer to the first element no matter. (Which is in fact why we can even write int param[] with an incomplete array size.)

    You could improve type safety by requiring a pointer to the array instead:

    void func(int (*array)[10])
    {
    }
    
    int main(void)
    {
        int array[4]; 
        func(&array); // compiler error
        return 0;
    }
    

    But using array pointers as part of the function API is odd and unusual - it might make the code harder to read. And this makes "const correctness" impossible as well.

    The best combination of readability and type safety might be to use a pointer to variable-sized array instead:

    #include <stddef.h>
    
    void func (size_t size, int array[size])
    {
    }
    
    int main(void)
    {
        int array[3]; 
        func(4, array); // warning from gcc here
        return 0;
    }
    

    This pushes the responsibility of keeping track of the array size onto the caller and some compilers may produce warnings in case it has a chance to spot mismatch at compile-time.