1.定义二级指针
1. 定义二级指针变量的格式
数据类型 **二级指针变量名;
2. 二级指针变量的初始化:
二级指针变量指向的是一个一级指针变量,
因此对二级指针变量赋值时,赋值的是一级指针变量的地址。
数据类型 普通变量名 = 初始值;
数据类型 *一级指针变量名 = &普通变量名;
---> 一级指针变量指向普通变量对应的地址空间
2.1> 定义二级指针变量的同时进行初始化
数据类型 **二级指针变量名 = &一级指针变量名;
---> 二级指针变量指向一级指针变量对应的地址空间
2.2> 先定义二级指针变量,后对二级指针变量进行初始化
数据类型 **二级指针变量名 = NULL;
二级指针变量名 = &一级指针变量名
int a=100;
int *p = &a;
int **pp=&p;
//p=&a; *p=a=100; pp=&p; *pp=p=&a; **pp=*p=a=100;
int a = 100;
int *p = &a;
int **pp = &p;
--------------------
a ---> 变量a对应地址空间的值
*p ---> 指针变量p指向的地址空间的值,及变量a对应的地址空间的值
**pp ---> *pp : 二级指针变量pp指向的一级指针变量对应地址空间的值
---> 一级指针变量对应地址空间存放的是变量a的地址
---> *(*pp) ---> 指向变量a对应的地址空间的值,及变量a对应的地址空间的值
------------------------
&a ---> 变量a的地址
p ---> 取指针变量p中存储的地址,及变量a的地址
*pp ---> 取二级指针变量pp指向的地址空间的值,
及指针变量p对应地址空间的存储的变量a的地址
----------------------
&p ---> 取指针变量p对应的内存地址
pp ---> 取二级指针变量pp中存储的指针变量p的地址
-----------------------
&pp ---> 取二级指针变量pp对应的内存地址
2.二级指针和指针数组的关系
研究二级指针变量名:
int a = 100;
int *p = &a;
int **pp = &p;
pp : 二级指针变量名,
pp+1 : 偏移int *类型的大小 32位系统和偏移4个字节 64位系统偏移8个字节
*pp : 取二级指针变量pp指向的地址空间的值,及一级指针变量p存放的数据,及&a
*pp <=等价=> p
*pp+1 <=等价于=> p+1 : 偏移int类型的大小 *pp是&a *pp+1等价于 p+1 偏移a的类型大小 4个字节
研究指针数组名含义:
int a = 100, b = 200, c = 300, d = 400, e = 500;
int *p_arr[5] = {&a, &b, &c, &d, &e};
p_arr : 指针数组名,数组的每个元素都是int *类型
表示指针数组的首地址
p_arr+1:偏移指针数组元素的大小,及偏移int *类型的大小
p_arr[下标] <=等价=> *(p_arr+下标) : 取指针数组某个元素的值 数组元素都是地址
p_arr[下标]+1 <=等价=> *(p_arr+下标)+1 : 指针数组每个元素的类型为int *类型 表示的是数组元素的值&a &b ....所以偏移的是变量a b...的类型大小
偏移int类型的大小
可以使用二级指针指向一个指针数组,及使用指针数组名对二级指针变量名赋值。
二级指针变量名和指针数组名的区别:
二级指针变量名是一个变量,可以被修改,改变二级指针的指向。
指针数组名是一个常量,不可以被修改。
二级指针指向指针数组
int a = 100, b = 200, c = 300, d = 400, e = 500;
int *p_arr[5] = {&a, &b, &c, &d, &e};
int **pp=p_arr;
p_arr[下标] <=等价=> *(p_arr+下标)<==>*(pp+下标) : 取指针数组某个元素的值 元素的值也是地址是指向的其他变量的地址
p_arr[下标]+1 <=等价=> *(p_arr+下标)+1<==>*(pp+下标)+1 : 指针数组每个元素的类型为int *类型偏移int类型的大小
编写代码:验证二级指针变量名和指针数组名的关系。
#include <stdio.h>
int main(int argc, const char *argv[])
{
// 1. 验证二级指针变量名
int a = 100;
int *p = &a;
int **pp = &p;
// pp : 取二级指针变量中存放的一级指针变量的地址
// pp + 1 : 二级指针变量的运算,加1偏移int *类型的大小
printf("pp = %p\n", pp);
printf("pp + 1 = %p\n", pp+1);
// *pp <==> p : 取二级指针变量指向的一级指针变量对应的内存空间的值
// *pp + 1 <==> p + 1: 一级指针变量的运算,加1偏移int类型的大小
printf("&a = %p\n", &a);
printf("p = %p\n", p);
printf("*pp = %p\n", *pp);
printf("p+1 = %p\n", p+1);
printf("*pp+1 = %p\n", *pp+1);
// 2. 指针数组名的验证
int b = 200, c =300, d = 400, e = 500;
int *p_arr[5] = {&a,&b,&c,&d,&e};
printf("p_arr = %p\n", p_arr); // 指针数组的首地址
printf("p_arr + 1 = %p\n", p_arr + 1); // 偏移int *类型的大小
// 指针数组的每个元素都是int *类型
printf("p_arr[0] = %p\n", p_arr[0]); // 取指针数组第0个元素的值
// 指针数组的每个元素都是int *类型
printf("*(p_arr+0) = %p\n", *(p_arr+0)); // 取指针数组第0个元素的值
// 指针数组的每个元素都是int *类型
printf("p_arr[0]+1 = %p\n", p_arr[0]+1); // 偏移int类型的大小
printf("*(p_arr+0)+1 = %p\n", *(p_arr+0)+1); // 偏移int类型的大小
return 0;
}