我得到“不兼容的指针类型”,我不明白为什么

我有两种错误:

编译器的投诉

pr.c:在函数’main’中:

pr.c:20:2:警告:从不兼容的指针类型[默认启用]传递’printMatrix’的参数1

pr.c:9:6:注意:预期’const int(*)[80]’但参数的类型为’int(*)[80]’

pr.c:22:2:警告:从不兼容的指针类型[默认启用]传递’lights’的参数1

pr.c:10:6:注意:预期’const int(*)[80]’但参数的类型为’int(*)[80]’

似乎编译器抱怨在接受const的函数中接收非const,但我被告知这是使用const的正确方法…

 #include  #include  #define MAXCOL 80 #define MAXROW 20 #define randNormalize() srand(time(0)) void fillMatrix(int m[][MAXCOL], size_t rows, size_t cols); void printMatrix(const int m[][MAXCOL], size_t rows, size_t cols); void lights(const int m[][MAXCOL], size_t rows, size_t cols); int star(const int m[][MAXCOL], int row, int col); int main() { int m[MAXROW][MAXCOL]; randNormalize(); fillMatrix(m, 5, 5); printMatrix(m, 5, 5); lights(m, 5, 5); return 0; } void fillMatrix(int m[][MAXCOL], size_t rows, size_t cols) { int i, j; for(i = 0; i < rows; i++) for(j = 0; j < cols; j++) m[i][j] = rand()%21; } void printMatrix(const int m[][MAXCOL], size_t rows, size_t cols) { int i, j; for(i = 0; i < rows; i++) { printf("\n"); for(j = 0; j < cols; j++) printf("%d ", m[i][j]); } printf("\n"); } void lights(const int m[][MAXCOL], size_t rows, size_t cols) { int i, j; for(i = 1; i < rows - 1; i++) { printf("\n"); for(j = 1; j < cols - 1; j++) { if( star(m, i, j) ) printf("*"); else printf(" "); } } printf("\n"); } int star(const int m[][MAXCOL], int row, int col) { int i, j; int sum = 0; for(i = row - 1; i <= row + 1; i++) for(j = col - 1 ; j  10); } 

我正在寻找不使用指针的最佳解决方案,因为这是来自我们尚未涵盖它们的课程的练习(尽管我已经研究过它们)。

不幸的是,在C中没有从int[X][Y]const int[X][Y]隐式转换。 也没有从int (*)[Y]const int (*)[Y]隐式转换。

这是语言的缺陷; 没有技术理由不应该允许这种转换。 (C ++确实允许这种转换)。

你有两个选择,都没有吸引力:

  1. 让函数接受int而不是const int
  2. 在调用const int函数时编写一个printMatrix((const int (*)[MAXCOL])m, 5, 5); ,例如printMatrix((const int (*)[MAXCOL])m, 5, 5);

通常会使用选项1 ,我们只需要对多维数组没有const正确性。

问题

当你在函数调用中使用m时,它会衰减为指针。 m衰变的指针类型是int (*)[5] – 指向“5个int的数组”的指针。

给定fillMatrix的声明,期望的参数类型是int (*)[MAXCOL] ,即int (*)[80] – 指向“80个ints的数组”的指针。

这两种类型不兼容。

通过查看编译器期望指针的行为以及预期的内存布局,可以理解这两种类型不兼容的原因。

为了便于解释,我将把数组的大小更改为2和4。

对于

 int m1[2][2]; 

内存布局如下:

 m1[0][0] m1[1][1] | | +---+---+---+---+ | | | | | +---+---+---+---+ 

如果你声明一个指针那个数组,

 int (*p1)[2] = m1; 

指针透视图中的内存布局如下所示:

 p1 p1+1 p1+2 | | | vvv +---+---+---+---+ | | | | | +---+---+---+---+ 

现在,让我们创建一个大小为4 x 4的数组,并从指针的角度检查内存布局的外观。

 int m2[4][4]; 

内存布局:

 m2[0][0] m2[3][3] | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 

指针:

 int (*p2)[4] = m1; 

指针透视图中的内存布局如下所示:

 p2 p2+1 p2+2 p2+3 p2+3 | | | | | vvvvv +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 

如果比较指针算法如何用于两种不同的指针类型,您将看到:

就执行指针 – > int解引用之前这些指针的值如何偏移而言, p1[1][0]是完全不同的p2[1][0]

如果p1被视为与p2的类型相同,则指针算法很容易导致访问数组超出范围并将导致未定义的行为。

这就是为什么当期望的参数类型是int (*)[80]时,编译器不会使用int (*)[4]类型的指针。

有很多方法可以解决这个问题。 最简单的解决方案是使用

 int m[2][MAXCOL];