本期重点:指针的性质、本质和作用
指针是C语言变量的一种,总的来说,它和int或者char之类的变量类型没有什么显著的区别,唯一的重点在于,指针实际上是地址。可以说指针就是地址,它是一个专门用于存放地址的变量,下面我们简单的看一下这个东西怎么回事:
首先要明确的是,指针类型定义的时候,根据指针本身的性质和类型的不同可以划分到不同的领域,有的是整形指针比如int* a,有的是字符类型指针比如char* b,判断一个变量是否是指针变量,区别就在于它的类型后面有没有一个星号(*),如果有,那大概率应该就是个指针。类型和星号之间可以加任意的空格,不过最好不要加,因为可能会造成概念的混淆,一定要牢记一点,那就是指针a的类型是int*,这是一个整体,而不是说,int类型的*a是一个指针。至于这个符号的构成,有意思的一点在于,指针本身只能存放地址,因此它其实无所谓是什么类型,然而解引用的时候,对地址内内容的操作取决于它类型的效果,比如对char* a解引用,和对int* b解引用后,*a和*b操作的时候操作起来是不一样的,*a+1和*b+1的结果不同就能证明这一点。下面我们看一下:
#include<stdio.h>
int main()
{int num[3] = { 5 };int* pnum = #char* pNum = #*(pnum + 1) = 5;*(pNum + 1) = 5;printf("%p", pnum);printf("%p", pnum+1);return 0;
}
运行该代码调试之后,我们发现,num[0]的地址和指针pnum的内容是完全一致的,而取地址&num和它们也是完全一样的,由此可以知道,指针里存入的其实是对象的地址,尤其是对象的首位地址。比如num[0]这个东西,本身有四个字节,也就是说,它有四个地址,从上面运行的结果来看,就是从0x00000096da3ff588到0x00000096da3ff58b,但是真正传入pnum的其实只是num[0]的第一个字节的地址,也就是首位地址。
那么,为什么我说其实指针的类型对指针解引用后的操作才有影响呢?从上面内容来看,确实指针变量本身只能用于存储地址,看样子类型是什么问题不大,下面我们看一下指针类型对于它解引用后的操作的影响:
#include<stdio.h>
int main()
{int num[3] = { 5 };int* pnum = #char* pNum = #*(pnum + 1) = 5;//*(pNum + 1) = 5;printf("%p", pnum);printf("%p", pnum+1);return 0;
}
现在我们沉默一条语句之后进行调试看看对地址内内存内容的影响:
如果你把507行语句也沉默的话,你就会发现,只有那个928地址里面只有第一位是05,其他的都是00,而507行语句对05 00 00 00之后的一位也进行了修改,改成了05。为什么会跳过三位呢?因为pnum指针是int类型的,int类型占四个字节,因此这个指针+1的时候,就会在内存里跳过一个整形,也就是四个字节。下面我们解除对508行的沉默:
有了第508行的影响,我们发现,C38地址里面第一个由于初始化而变成05的字节后面马上又多了一个05,这就是508行导致的,因为pNum指针的类型是char*,char类型的长度是1字节,因此pNum+1会跳过一个char长度,也就是超过一个字节。
由此我们可以看出,指针的类型对于它存储地址是没有影响的(这一点可以通过对int*、char*、float*等等进行sizeof操作看出,长度是一样的),只在它解引用并进行进一步操作的时候影响比较大。
还有一件事,如果你玩原神的话,你有没有感觉空(Aether)和荧(Lumine)的关系不纯洁?在睡前故事结尾的剧情里,他俩似乎有骨科,我不确定,但是我觉得很香,这很好。