C语言中int**m与int*m[N]兼容却不兼容int m[N][N]的原因
为什么C语言中
int** m和int*m[N]兼容,却和int m[N][N]不兼容? 核心差异在于这几种类型的内存结构和语义完全不同,下面逐个拆解:
1. int*m[N]的本质:指针数组
int*m[N]是一个数组,数组里的每个元素都是int*类型的指针。比如int*m[3],就是3个指向int的指针在内存中连续排列,每个指针可以独立指向任意int变量或int数组的某个位置。
当你把int*m[N]类型的变量赋值给int** m时,会触发C语言的数组到指针的隐式转换:数组名会自动转换成指向数组第一个元素的指针。因为int*m[N]的第一个元素是int*,所以转换后的类型就是int**,完全匹配,因此两者兼容。
2. int m[N][N]的本质:连续二维数组
int m[N][N]是真正的二维数组——本质是一个数组,数组的每个元素是int[N]类型的一维数组。比如int m[2][3],它的内存是连续的6个int值直接排列,没有任何中间指针层:{1,2,3,4,5,6}会被依次存在一块连续内存里。
作为数组名,m会被隐式转换成int(*)[N]类型(指向包含N个int的数组的指针),而不是int**。
3. 为什么int**和int m[N][N]不兼容?
两者的内存布局天差地别:
int**指向的是一个int*指针,这个指针再指向具体的int值——中间多了一层指针间接层。比如int** p,p存储的是另一个指针的地址,那个指针才指向int数据。int m[N][N]是连续的int数据块,没有中间指针。如果强行把int m[N][N]转换成int**,程序会把m指向的前几个int值当成指针地址去访问,这必然会导致内存访问错误。
4. 为什么int m[][N]能转成int(*m)[],却不能转成int**?
int m[][N]本质还是连续二维数组,数组名转换后是int(*)[N]——这个指针的步长是N个int的大小,正好匹配二维数组的内存布局(每次移动一个一维数组的长度)。而int**的步长是一个指针的大小,和二维数组的结构完全不匹配,自然无法兼容。
举个实际代码例子:
// 指针数组和int**兼容 int a = 1, b = 2; int* ptr_arr[2] = {&a, &b}; int** pp = ptr_arr; // 合法,ptr_arr隐式转成int** // 二维数组不能转成int** int mat[2][2] = {{1,2},{3,4}}; int** qq = mat; // 非法,mat转成int(*)[2],和int**类型不匹配 int(*rr)[2] = mat; // 合法,类型完全匹配
内容的提问来源于stack exchange,提问作者ImRobb
相关产品推荐
相关产品推荐

