指针:指针本质上是一个存储内存地址的变量。
这句话说虽然起来容易但是理解起来也确实不难。很多同学在初学C语言的时候都接触过指针,知道指针存储的是一个内存地址,也知道指针能访问内存,但是内存是一段存储空间,指针只是存储了内存空间的起始地址,想要访问这段内存,还需要知道控制的内存空间有多大,如何获取空间的大小信息呢?答案是通过指针类型判断指针可以访问的内存范围,例如int类型的指针访问的内存范围是4个字节,double 类型指针访问的内存范围是8个字节。这样通过唯一的内存起始地址和访问内存大小就可以控制一段内存。对于一级指针理解到这里已经能够应付绝大多数情况了。还有一个常见的操作术语是解引用。解引用指针意味着通过该指针获取它所指向的内存位置上的数据值
指针作为一个变量,本身也是有地址的,这时候如果有另一个变量存储了指针的地址....那么这个变量就被称为二级指针,以此类推,还会有三级指针四级指针等等。不过常用的最多到二级指针,再高就不利于凡人理解了。 另外规定任何指针类型的变量大小都是8个字节,牢记这点,后面会很有用。
很多初学者都会对高级指针感到疑惑,例如 int ****p, 如何理解*p, **p, ***p。下面会举个例子简单的说明一下。
int a = 10;
int *b = &a;
int **c = &b;
int ***d = &c;
printf("b=%p, c=%p, d=%p\n", b, c, d);
运行结果是:
结果很明显,无论几级指针,指着的本质都是存储内存地址的变量。
可能还有一些同学见过指针类型的强制转换,例如直接把一个一级指针转换为二级三级甚至是四级指针,这个转换显得非常匪夷所思,因为在上面的例子中,似乎k级指针指向的是k-1级指针的地址,难道编译器帮助我们自动定义了多级指针?直接编写程序实验一下就可以知道了。
int a = 10;
int *b = &a;
int **c = &b;
int ***d = &c;
int *****e = (int *****)&a;
printf("b=%p, c=%p, d=%p\n", b, c, d);
printf("e=%p\n", e);
运行结果:
这个时候出现了一件匪夷所思的事情,我们定义的5级指针,怎么和一级指针b地址是一样的呢?
那这个五级指针的意义是什么?对这个五级指针解引用会出现什么呢?
继续打印输出,我们看一下这个五级指针,四级指针和三级指针到底指向的什么
int a = 10;
int *b = &a;
int **c = &b;
int ***d = &c;
int *****e = (int *****)&a;
printf("b=%p, c=%p, d=%p\n", b, c, d);
printf("e=%p\n", e);
printf("*e=%p\n",*e);
printf("**e=%p\n",**e);
程序运行结果:
从结果来看,五级指针e存储的是一个内存的地址,对五级指针解引用后获得的四级指针,值是0xa0000000a,就是16进制下的10,这个值就是我们定义的a的值,三级指针直接没有打印出来,程序就报错了:segmentation fault 。翻译一下就是段错误。一般是访问了不存在的内存地址会出现这个。
所以结果很明显了,编译器不会帮我们自动定义好多级指针。对于编译器来说,无论是几级指针,直接输出指针的值,一定是个地址。对指针进行解引用,不一定会成功。如果k级指针存储的值是个地址,那么对其进行解引用是没有问题的,如果存储的不是地址,解引用会失败。
再回头看下解引用,本质就是把指针存储的值当作地址来使用,无论是不是地址。
这种多级指针的一个用处就是绕过结构体的控制,直接访问结构体的成员。举个例子:
typedef struct test_struct
{
double a;
double b;
double c;
}test_struct;
test_struct s1 = {10.0, 50.9, 70.1};
test_struct ** ptr1 = (test_struct **)&s1;
for(int i=0; i<3;++i)
{
printf("%f\n", *(ptr1+i));
}
运行结果:
这个例子中我们就通过了二级指针绕开了结构体的限制直接访问了结构体的成员变量!事实上不仅是访问,修改也可以。
需要注意的是,指针地址加1实际上意味着指针向前移动到下一个相同类型的数据的起始位置,而不是在地址的实际值上加了个1。
总结:几级指针不重要,表面是十级指针,实际上也可能是二级指针,无论是几级指针,最终存储的一定是地址。对指针的操作很重要,当前指针存储的是地址才能进行解引用,才能进行地址的偏移计算,解引用后得到的如果不是地址,即使还是指针,也不能再进行解引用了。
这是一条吃饭推文,由挨踢零声赞助