一, 二级指针
指向指针的指针是一种多级间接寻址的形式, 或者说是一个指针链. 通常, 一个指针包含一个变量的地址. 当我们定义一个指向指针的指针时, 第一个指针包含了第二个指针的地址, 第二个指针指向包含实际值的位置.
1.jpg
一个指向指针的指针变量必须如下声明, 即在变量名前放置两个星号. 例如, 下面声明了一个指向 int 类型指针的指针:
int **p;
当一个目标值被一个指针间接指向到另一个指针时, 访问这个值需要使用两个星号运算符, 如下面实例所示.
例 1:
- #include <stdio.h>
- int main ()
- {
- int a;
- int *ptr;
- int **pptr;
- a = 100;
- /* 获取 a 的地址 */
- ptr = &a;
- /* 使用运算符 & 获取 ptr 的地址 */
- pptr = &ptr;
- /* 使用 pptr 获取值 */
- printf("a = %d\n", a);
- printf("*ptr = %d\n", *ptr );
- printf("**pptr = %d\n", **pptr);
- return 0;
- }
运行结果:
- a = 100
- *ptr = 100
- **pptr = 100
可以进一步查看一下指针的地址.
例 2:
- #include <stdio.h>
- int main()
- {
- int a = 5;
- int *ptr = &a;
- int **ptr2 = &ptr;
- printf("%d,%d,%d\n", **ptr2, *ptr, a);
- printf("%p, %p, %p\n", *ptr2, ptr, &a);
- printf("%p, %p\n", ptr2, &ptr);
- printf("%p\n", &ptr2);
- return 0;
- }
运行结果:
- 5,5,5
- 0061ff0c, 0061ff0c, 0061ff0c
- 0061ff08, 0061ff08
- 0061ff04
从结果可以看出,**ptr2, ptr, 指向了 a 的值. 一级指针 ptr2 和 ptr 则指向了 a 的地址. 二级指针 ptr2 指向了一级指针 ptr 的地址, ptr2 本身的地址则是 0x0061ff04.
二, 多级指针
既然有一级指针和二级指针, 就有三级指针, 四级指针, 五级指针......
以三级指针为例, 三级指针是 "指针的指针的指针", 或者叫 "指向'指向指针的指针'的指针".
因为多级指针不好理解, 并且在编程时容易写错, 所以建议尽量不要使用二级以上的指针.
三, 指针指向 NULL
经常看到给一级指针赋值为 NULL 的程序. 比如下面的程序.
例 3:
- #include <stdio.h>
- int main()
- {
- int a = 5;
- int *p = NULL;
- p = &a;
- printf("%p,%p,%p,%d", &p, p, &a, *p);
- return 0;
- }
运行结果为:
0061ff08,0061ff0c,0061ff0c,5
这里定义了指针后, 把指针指向 NULL. 这是一种安全的写法. NULL 值为 0, 被放在内存里地址为 0x0 的区域. 这是一块安全的内存区域. 程序里 p 先指向了这块安全区域, 然后再指向变量 a 的地址.
最后打印出来结果可以看出, p 本身的地址为 0061ff08;p 所指向的地址即 a 的地址为 0061ff0c;*p 为 a 的值, 即 5.
字符'\0'的值也是 0.
虽然值都是 0, 但意义不一样:
(1)0 表示数字
(2)'\0'表示字符串结束符.
(3)NULL 表示空对象或空指针.
四, NULL 内存区域不可读写
0x0 这块内存区域是不可写的. NULL 这个值在一些编译器连读取都不能.
下面用 Codeblocks 集成开发环境测试一下.
例 4:
- #include <stdio.h>
- int main()
- {
- int *p = NULL;
- printf("%p, %p\n", &p, &(*p));
- printf("%d\n", *p);
- return 0;
- }
运行结果:
- 0x6dfefc 00000000
- Process returned -1073741819 (0xC0000005)
从运行结果可以看到, 打印出了 p 指针本身的地址, 为 0x6dfefc; 也打印出了 NULL 所在的地址 00000000. 但是, 没有打印出 p, 而是报 "Process returned -1073741819 (0xC0000005)" 的错误. 这里 p 就是 NULL 或 0. 可见在 Codeblocks 开发环境里 NULL 内存不能读取.
再看看二级指针的情况.
例 5:
- #include <stdio.h>
- int main()
- {
- int a = 5;
- int *ptr = &a;
- int **ptr2 = NULL;
- *ptr2 = ptr;
- printf("run ok\n");
- return 0;
- }
这个程序运行时报错. 下面来分析一下原因:
第 6 行定义了一个 1 级指针 ptr, 接下来的程序里若出现 ptr 表示指针所指向的地址里的值. 即 ptr 是一个 1 级指针, ptr 是一个整数值.
第 7 行定义了一个 2 级指针 ptr2, 接下来的程序里若出现 ptr2 表示 ptr2 所指向的一级指针的地址, 若出现 ptr2 表示 2 级指针 ptr2 所指向的一级指针指向的地址里的值. 简单地说就是 ptr2 是一个二级指针, ptr2 是一级指针, ptr2 是一个整数值.
第 9 行 ptr2 = ptr, 表示一级指针指向一级指针, 逻辑上没有问题. 那么为什么会错呢?
原因在于第 7 行的 ptr2 = NULL, 这表示 ptr2 指向的地址为 0x0, 即 ptr2 = 0x0.0x0 是一个特殊的内存块, 不能读写, 要对他赋值 * ptr2 = ptr, 显然会出错.
来源: http://www.jianshu.com/p/2b0cfdd02dd6