指向指针的指针数组与指向数组的指针指针类型不匹配问题排查
指针指针数组与指向数组的指针指针的类型差异及解决方案
场景与问题
现有如下代码,通过单个整数变量创建指向指针的指针数组arrayABC:
int A = 1; int B = 2; int C = 3; int *ptA = &A; int *ptB = &B; int *ptC = &C; int **arrayABC[] = { &ptA, &ptB, &ptC };
同时有整数数组DEF:
int DEF[] = {4,5,6};
希望将DEF包装为与arrayABC接口一致的int **[]类型数组arrayDEF,并归入父数组arrayGlobal:
int ***arrayGlobal[] = {arrayABC,arrayDEF};
预期通过**arrayGlobal[1][i]访问DEF[i],但尝试的单行写法编译无错但运行时触发段错误:
int **arrayDEF[] = &(int *){&DEF};
核心疑问:arrayDEF的类型(指向数组的指针指针)与arrayABC的类型(指向指针的指针数组)是否相似但不等价?
类型差异分析
你的怀疑完全正确,两者本质完全不同:
arrayABC是int **[]类型,即指向指针的指针数组:每个元素是int**,存储的是独立int*变量的地址(如&ptA指向ptA这个指针变量,而ptA的值是&A)。- 错误写法中的
arrayDEF实际是仅包含1个元素的int**[]数组,这个元素是指向临时int*变量的指针:复合字面量(int *){&DEF}生成一个临时int*变量,值为数组DEF的首地址;&(int *){&DEF}取这个临时变量的地址作为arrayDEF的唯一元素。
当访问arrayGlobal[1][1]时,实际是越界访问仅含1个元素的arrayDEF数组,直接触发段错误。
另外你误以为(int *[]){&array}等价于{&array[0], &array[1], &array[2]},这也是错误的:前者是仅含1个元素的int*数组(元素为数组array的首地址),后者是含3个元素的int*数组(元素为数组每个元素的地址),两者元素数量、内容完全不同。
简洁解决方案
要创建与arrayABC结构一致的arrayDEF,必须为DEF的每个元素地址创建对应的int*变量,再取这些变量的地址组成int**[]数组。面对大量元素时,可通过宏自动生成:
// 宏定义:为数组生成对应的指向指针的指针数组 #define MAKE_PTR_ARRAY(arr, len) \ int *arr##_ptrs[len]; \ do { \ for (int i = 0; i < len; i++) { \ arr##_ptrs[i] = &arr[i]; \ } \ } while(0); \ int **arr##_array[len]; \ do { \ for (int i = 0; i < len; i++) { \ arr##_array[i] = &arr##_ptrs[i]; \ } \ } while(0)
使用示例:
// 为DEF数组生成符合要求的arrayDEF(实际变量名为DEF_array) MAKE_PTR_ARRAY(DEF, 3); // 归入父数组 int ***arrayGlobal[] = {arrayABC, DEF_array}; // 正常访问 printf("D = %d\n", **arrayGlobal[1][0]); // D = 4 printf("E = %d\n", **arrayGlobal[1][1]); // E = 5 printf("F = %d\n", **arrayGlobal[1][2]); // F = 6
该宏会自动生成存储DEF各元素地址的int*数组,再生成指向这些指针的int**数组,无需手动逐个定义指针变量。
内容的提问来源于stack exchange,提问作者Steens
相关产品推荐
相关产品推荐

