C语言中为何无法使用二维匿名数组初始化指针数组

首先看可以正常运行的一维匿名数组赋值代码:
int *p = ( int[] ){ 1, 2, 3, 4 };
按照这个逻辑,尝试将二维匿名数组赋值给指针数组的代码如下,但是无法通过编译:
int *p[]= (int [][3]) { {1,2,3},{10,20,30} };
将左侧改为指向数组的指针后,代码可以正常运行:
int (*p)[]= (int [][3]) { {1,2,3},{10,20,30} };
核心原因:类型不匹配,内存布局完全不同
- 一维场景能正常运行的本质是C语言的数组隐式退化规则:
(int[]){1,2,3,4}是int[4]类型的匿名数组,用于赋值场景时会自动退化为指向首元素的指针,首元素类型是int,退化后的指针类型就是int*,和左侧指针p的类型完全匹配,因此可以正常赋值。 - 二维场景下,右侧的
(int[][3]){{1,2,3},{10,20,30}}是int[2][3]类型的匿名二维数组,本质是「元素为int[3]类型的一维数组」。按照退化规则,它会退化为指向自身首元素的指针,首元素类型是int[3],因此退化后的指针类型是int (*)[3](指向长度为3的int数组的指针)。 - 左侧写的
int *p[]是int类型指针构成的数组,本质是数组,每个元素都是int*类型的指针。它和右侧的二维数组内存布局完全不兼容:int[2][3]的内存是连续排布的6个int值:1、2、3、10、20、30,整块内存里没有存储任何指针值int*[2]的内存是连续排布的2个指针变量,每个指针需要存储一个内存地址,两者没有办法直接做内存层面的匹配,自然无法通过编译。
- 而
int (*p)[]是指向int数组的指针,类型和二维数组退化得到的int (*)[3]兼容(未指定长度的数组指针可以接收同元素类型、固定长度的数组指针),类型匹配因此可以正常运行。
如果确实要给指针数组赋值匿名的二维结构,需要显式构造元素为int*的匿名数组,写法如下:
int *p[] = (int*[]) { (int[]){1,2,3}, (int[]){10,20,30} };
此时右侧是int*[2]类型的匿名指针数组,每个元素都是一个匿名一维int数组退化得到的int*指针,和左侧类型完全匹配,可以正常编译运行。
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

