二级指针
简单来说,二级指针存储一级指针的地址,指向一级指针。
double a = 0, b = 0, c = 0, d = 0;
double* p0 = &a;
double* p1 = &b;
double* p2 = &c;
double* p3 = &d;
double** s = &p0;
如果a、b、c、d的地址是连续分配的,指针p0、p1、p2、p3的地址也是连续分配的,那么下面三种情况:
s + 1; //&p1 移动4个字节 类型是double**
*s + 1; //&b 移动8个字节 类型是double*
**s + 1; //a + 1 = 1 类型是double
我们知道,指针加一的作用是加上其指向内容的数据类型的长度。
s开始指向的是一级指针p0,p0是指针,长度是4个字节,那么s+1就会移动4个字节,所以s指向了p1。
*s是s解引用的形式,也就是p0指针本身,而p0指针指向变量a,变量a的长度是8个字节,那么 *s+1就会移动8个字节,所以 *s(等同于p0)指向了b。
**s 是 *s解引用的形式,也就是变量a,那么 **s+1就是a变量本身加一,所以变量a由0变为1。
二级指针的应用:二维数组
数组指针和指针数组
int main() {
int a = 0, b = 1, c = 3, d = 4;
int* pr[4] = { &a,&b,&c,&d }; //指针数组
int(*s)[4] = nullptr; //数组指针
int ar[4] = { 1,2,3,4 };
s = &ar;
return 0;
}
由程序可知,指针数组pr就是四个int*类型变量构成的一个数组,性质和其他类型的数组一样。
数组指针通俗来讲是指向数组的指针,将数组看成一个整体,这个指针指向的是整个数组。也就是说,定义成int(*s)[4],s就只能指向元素个数为4,类型为int的数组,不能指向其他类型的数组,或是元素数量不是4的数组。
数组地址和数组首元素地址
int main() {
int ar[4] = { 1,2,3,4 };
int* p0 = ar;
int* p1 = &ar[0];
int(*s)[4] = &ar;
return 0;
}
我们知道,数组名就是数组首元素的地址,所以p0和p1是完全等价的,都存储数组首元素地址;通过指针数组定义方式的s指向的整个数组,存储数组的地址,虽然从结果上来看,数组首元素的地址和数组的地址相同,也就是说p0、p1、s中存储的地址都是相同的,但是区别在于它们加一的能力不同。p0、p1加一是相对于数组首元素地址的,加一是加数组中元素类型的长度;s是相对于数组地址的,加一是加数组的长度。
数组地址可以转化为数组首元素地址。s此时指向ar数组(s=&ar),那么*s就指向数组首元素(*s=ar)。
一维数组和二维数组
int main() {
int ar[4] = { 1,2,3,4 };
int size1 = sizeof(ar); //16字节
int* p1 = ar; //数组首元素的地址
int(*s1)[4] = &ar; //数组的地址
int br[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
int size2 = sizeof(br); //48字节
int(*p2)[4] = br; //数组首元素的地址
int(*s2)[3][4] = &br; //数组的地址
return 0;
}
如果说一维数组是一个一个变量组成的集合的话,那么二维数组就是一个一个一维数组组成的集合。br[3][4]可以看成是由三个一维数组构成,每个一维数组有四个变量。这样我们把二维数组每一个元素都视为一维数组,那么二维数组的首元素地址就是第一个一维数组的地址。我们如何定义一个指向一维数组的指针呢?就是利用指针数组!所以代码int(*p2)[4] = br是指向二维数组首元素的地址就容易理解了。如果要指向整个二维数组,采用int(*s2)[3][4] = &br的形式,这说明s2指向这样一个数组,这个数组是三行四列的二维数组,且数组的类型是int型。
数组下标形式和指针形式的转化
int main() {
int ar[4] = { 1,2,3,4 };
printf("%d\n", ar[2]); //3
printf("%d\n", *(ar + 2)); //3
int br[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
printf("%d\n", br[2][3]); //12
printf("%d\n", *(*(br + 2)+3)); //12
return 0;
}
br作为二维数组首元素的地址,br+2首先移动指针指向第三个元素,也就是第三个一维数组的首元素地址处,解引用*(br+2)将其转换成指向这个一维数组首元素的指针,*(br+2)+3移动指针指向一维数组中第四个元素,解引用 *( *(br + 2)+3)就是这个元素的值。
二维数组的实例
int main() {
int ar[5][2] = { 1,2,3,4,5,6,7,8,9,10 };
int(*p)[2] = &ar[1];
int* s = ar[1];
printf("%d \n", p[1][3]); //8
printf("%d \n", s[3]); //6
return 0;
}
结合前面的知识,该程序的输出结果容易得出。