二级指针
前面几节所学的指针都是一级指针,其实指针还可以指向一个指针,即指针中存储的是另一个指针变量的地址,这样的指针称为二级指针,使用二级指针可以间接修改一级指针的指向,也可以修改一级指针指向的变量的值。
定义二级指针的格式如下:
变量类型 **变量名;
上述语法格式中,变量类型就是该指针变量指向的指针变量所指变量的数据类型,两个符号“*”,表明这个变量是个二级指针变量。
通过二级指针可以直接修改一级指针指向的变量的值,也可以间接修改一级指针的指向。下面以案例的形式介绍二级指针这两方面的作用。
1、通过二级指针间接修改变量的值
下面通过一个案例来演示如何使用二级指针直接修改变量的值,如例1所示。
例1 addr.c
1 #include <stdio.h>
2 int main()
3 {
4 int a = 1; //整型变量
5 int* p = &a; //一级指针p,指向整型变量a
6 int** q = &p; //二级指针q,指向一级指针p
7 printf("变量a的地址:%p\n",&a);
8 printf("一级指针p的地址:%p\n", p);
9 printf("二级指针q存储的值:%p\n", *q);
10 printf("二级指针q的地址:%p\n", q);
11 **q = 2; //二级指针间接改变,
12 printf("变量a的值%d\n", a);
13 return 0;
14 }
例1运行结果如图1所示。
图1 例5-6运行结果
在例1中,指针q是一个二级指针,其中存储一级指针p的地址,而p中存储整型变量a的地址,第11行代码通过间接访问运算符“”间接修改二级指针变量q中存储的指针所指向的值,从而修改变量a的值。由图5-10可知,变量a的值被修改成功。它们之间的逻辑关系如图2所示。
图2 指向指针变量的指针
从图2运行结果可以清晰的发现变量a的地址、一级指针p的地址和二级指针存储的地址值是一样的。
2、通过二级指针改变一级指针的指向
二级指针除了直接改变变量的值以外,也可以改变一级指针的指向,下面通过一个案例来演示如何通过二级指针改变一级指针的指向,如例2所示。
例2 poniter.c
1 #include <stdio.h>
2 int main()
3 {
4 int a = 1; //整型变量
5 int* p = &a; //一级指针p,指向整型变量a
6 int** q = &p; //二级指针q,指向一级指针p
7 int b = 3;
8 printf("变量a的地址:%p\n", &a);
9 printf("一级指针p的地址:%p\n", p);
10 printf("二级指针q存储的值:%p\n", *q);
11 printf("二级指针q的地址:%p\n", q);
12 printf("================================\n");
13 *q = &b; //修改一级指针的指向
14 printf("变量a的地址:%p\n", &a);
15 printf("变量b的地址:%p\n", &b);
16 printf("一级指针p的地址:%p\n", p);
17 printf("二级指针q存储的值:%p\n", *q);
18 printf("二级指针q的地址:%p\n", q);
19 printf("指针p指向地址存储的值%d\n", *p);
20 return 0;
21 }
例2运行结果如图2所示。
图2 例2运行结果
在例2中,第4~5行代码定义int类型变量a,取其地址赋值给一级指针变量p;第6行代码取一级指针变量p的地址赋值给二级指针q,则二级指针q的值是一级指针变量p的内存地址;第8~11行代码分别输出变量a的地址、一级指针p的地址、二级指针q存储的值以及二级指针q的地址。由图2可知,二级指针q存储的值与一级指针p的地址以及变量a的地址是相同的。
在例2中,通过间接访问运算符“”,修改二级指针的指向,即第13行代码使二级指针变量q中保存的一级指针变量p指向变量b。它们之间的逻辑关系如图3所示。
图3 二级指针改变指向关系
第14~19行代码分别输出变量a的地址、变量b的地址、一级指针变量p的地址、二级指针q存储的值及其地址。从图3的输出结果可以清晰的看到一级指针变量p、二级指针变量q存储的值和变量b的地址是相同的。