将二维数组传递给常量参数的函数
我从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 );