int array[] = { 1,2,3,4 }; //数组本质是个int指针,指向第一个元素
int* int_ptr = array; //int指针指向数组的第一个元素
int& int_ref = *int_ptr; //第一个元素的引用
printf("%p %p %p\n", array, int_ptr, &int_ref);
printf("%p %p %p\n", array+1, int_ptr+1, &int_ref+1);
// 输出
00EFF8D0 00EFF8D0 00EFF8D0
00EFF8D4 00EFF8D4 00EFF8D4
数组本身是一个元素指针,除了元素类型信息以外不携带任何关于这个数组的信息。
但是有意义的是对数组取地址得到却不是一个int**这么简单:
// int(*array_ptr)[3] = &array; // 编译器会报错,int(*)[4]类型的值不能用于初始化int(*)[3]
类型的实体
// int** int_p_p = &array; // 编译器会报错,int(*)[4]类型的值不能用于初始化int**类型的实体
看来编译器会检查右值的类型,这说明数组的指针携带了所指向的数组的类型和长度信息,并不是简单将数组当作int指针又取了一次地址而已 。
借两张图来帮助记忆。来自https://www.cnblogs.com/zero-waring/p/12776044.html的两张图
定义数组的指针和引用的写法比较复杂,如果不用等价声明typedef或者using的方式的话。
int(*array_ptr_1)[4] = &array; // 定义一个长为4的int型数组的指针,并将array的地址赋给这个指针
// 这个看起来有点复杂的声明的解读:
// (*array_ptr_1) 说明array_ptr_1是一个可以解引用的变量
// (*array_ptr_1)[4]说明解引用之后是一个四个元素的数组, int xxxxxx说明这个数组的元素类型是int
// ---(c++primer)
int(&array_ref_1)[4] = array; // 几乎同等烧脑的数组引用的声明方式。
// 改用数组等价声明方式
using a_int_4 = int[4];
a_int_4* array_ptr_2 = &array; // 这种声明方式可以产生和array_ptr_1一摸一样的数据类型
a_int_4& array_ref_2 = array;
int array_ptr_3[2][4]; //多维数组的声明,按理说array_ptr_3应该是一个指向int[4]的指针
// 下面将其地址和偏移特性都打出来看一下
printf("%p %p %p %p %p\n", array_ptr_1, array_ptr_2, &array_ref_1, &array_ref_2,array_ptr_3);
printf("%p %p %p %p %p\n", array_ptr_1 + 1, array_ptr_2 + 1, &array_ref_1+1, &array_ref_2+1, array_ptr_3 + 1);
00B3F768 00B3F768 00B3F768 00B3F768 00B3F6F8
00B3F778 00B3F778 00B3F778 00B3F778 00B3F708
五者的偏移都是16bytes,说明指针携带了对象的元素和长度信息。
跟函数的形参、返回值声明搅和在一起之后就更加烧脑了。
void func(int( *array_ptr)[4], int(& array_ref)[4]); // 做形参的时候还好,跟上面一样的
做返回值的时候就...
int(*func_returns_array_ptr())[4]{
int (*xx)[4] = new int[3][4];
printf("%p <--malloc in func_returns_array_ptr\n", xx);
return xx;
}//😂
int(&func_returns_array_ref())[4]{
int(*xx)[4] = new int[3][4];
printf("%p <--malloc in func_returns_array_ref\n", xx);
return *xx;
}//🤣🤣🤣
// 调用也古怪
int(*array_ptr_ret)[4] = func_returns_array_ptr();
int(&array_ref_ret)[4] = func_returns_array_ref();
printf("%p %p\n", array_ptr_ret, &array_ref_ret);
printf("%p %p\n", array_ptr_ret + 1, &array_ref_ret + 1);
printf("%p <-array_ptr_ret\n",array_ptr_ret);
delete array_ptr_ret;
printf("%p <-&array_ref_ret\n", &array_ref_ret);
delete &array_ref_ret;
好在结果看起来是对的
01496BB0 <--malloc in func_returns_array_ptr
014968D8 <--malloc in func_returns_array_ref
01496BB0 014968D8
01496BC0 014968E8
01496BB0 <-array_ptr_ret
014968D8 <-&array_ref_ret
还是老老实实用typedef或者using吧亲。