我得到“不兼容的指针类型”,我不明白为什么
我有两种错误:
编译器的投诉
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 ++确实允许这种转换)。
你有两个选择,都没有吸引力:
- 让函数接受
int
而不是const int
- 在调用
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];