一、二级指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
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:
1 #include <stdio.h>2 3 int main()4 {5 int a = 5;6 int *ptr = &a;7 int **ptr2 = NULL;8 9 *ptr2 = ptr;10 11 printf("run ok\n");12 13 return 0;14 }
这个程序运行时报错。下面来分析一下原因:
第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,显然会出错。
作者:海天一树X
链接:https://www.jianshu.com/p/2b0cfdd02dd6