将二维数组传递给常量参数的函数

我从C Primer Plus了解到,如果要保护数组不被函数意外修改,则应在函数定义头部的指针声明之前添加const修饰符。

遵循这个明智的build议,在下面的最小的例子中,我试图将一个非常量的二维数组array传递给Sum2D函数,其中的一个参数是一个pointer-to-const-int[2]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; } 

但是,如果不发出以下警告, gcc无法成功编译此代码:

 $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)为什么警告?

2)如何消除“噪音”?(除了在array声明中joinconst )。

(如果array和函数都使用一维数组,则不会有警告。)

系统信息:

Ubuntu 14.04LTS

编译器:gcc 4.8.2

这是Cdevise中一个不幸的“错误”。 T (*p)[N]不会隐式转换为T const (*p)[N] 。 您将不得不使用丑陋的强制转换,或者使函数参数不接受const


乍一看,这种转换看起来应该是合法的。 C11 6.3.2.3/2:

对于任何限定符q ,可以将指向非q限定types的指针转​​换为指向q类限定版本的指针;

不过也看C11 6.7.3 / 9(在C99中是/ 8):

如果数组types的规范包含任何types限定符,则元素types是限定的,而不是数组types。

这最后一个报价说, int const[4] 被认为是int[4]const限定版本。 实际上它是一个非const限定的4个const int数组。 int[4]int const[4]是不同元素types的数组。

所以6.3.2.3/2实际上不允许将int (*)[4]转换为int const (*)[4]


另一个奇怪的情况,这个问题与const和数组显示出来是当typedefs正在使用; 例如:

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

这将导致编译器错误: X const x表示x是常量,但它指向一个非const int数组; 而int const x[5]意味着x不是const,而是指向一个const int数组!

在这里进一步阅读,感谢@JensGustedt

您可以在调用函数的同时键入转换数组。 它不会自动将非const转换为const。 你可以使用这个。

 Sum2D( (const int (*)[])array, ROWS );