Search code examples
carrayspointersgcc-warning

Pass a two dimensional array to a function of constant parameter


I learned from C Primer Plus that if you want to protect an array from being accidentally modified by a function, you should add const modifier before the pointer declaration in the header of function definition.

Following this sensible advice, in the following minimal example, I'm trying to pass a non-constant two-dimensional array array to the function Sum2D, one parameter of which is a pointer-to-const-int[2].

#include <stdio.h>
#define ROWS 2
#define COLS 2
int Sum2D(const int ar[][COLS], int rows); //use `const` to protect input array
int main(void)
{
    int array[ROWS][COLS]={{1,2},{3,4}}; //the non-constant array

    printf( "%d\n", Sum2D(array,ROWS) );

    return 0;
}

int Sum2D(const int ar[][COLS], int rows)
{
    int total=0;
    int i,j;
    for( i=0 ; i<rows ; i++ )
    {
        for( j=0 ; j<COLS ; j++ )
        {
            total+=ar[i][j];
        }
    }
    return total;
}

However, gcc cannot successfully compile this code without issuing the following warnings:

$gcc -ggdb3 -Wall -Wextra -o test test.c

test.c: In function ‘main’:
test.c:16:2: warning: passing argument 1 of ‘Sum2D’ from incompatible pointer type [enabled by default]
  printf( "%d\n", Sum2D(array,4) );
  ^
test.c:4:5: note: expected ‘const int (*)[4]’ but argument is of type ‘int (*)[4]’
 int Sum2D(const int ar[][COLS], int rows);
     ^

1) Why the warning?

2) How can I eliminate the "noise"?(Apart from adding const to array declaration.)

(If the array and function both use one-dimensional array, there is no warning.)

System information:

Ubuntu 14.04LTS

Compiler: gcc 4.8.2


Solution

  • This is an unfortunate "bug" in C's design; T (*p)[N] does not implicitly convert to T const (*p)[N]. You will have to either use an ugly cast, or have the function parameter not accept const.


    At first sight it looks like this conversion should be legal. C11 6.3.2.3/2:

    For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type;

    However also look at C11 6.7.3/9 (was /8 in C99):

    If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.

    This last quote says that int const[4] is not considered to be a const-qualified version of int[4]. Actually it is a non-const-qualified array of 4 const ints. int[4] and int const[4] are arrays of different element types.

    So 6.3.2.3/2 does not in fact permit int (*)[4] to be converted to int const (*)[4].


    Another weird situation where this issue with const and arrays shows up is when typedefs are in use; for example:

    typedef int X[5];
    void func1( X const x );
    void func1( int const x[5] );
    

    This would cause a compiler error: X const x means that x is const, but it is pointing to an array of non-const ints; whereas int const x[5] means x is not const but it is pointing to an array of const ints!

    Further reading here, thanks to @JensGustedt