学C语言初期,相信大家都会被指针所困扰,不知道怎么去理解指针,本人在经过深入学习指针后终于理解单指针和双指针的相关知识,现整理给大家,同时也是给自己学笔记,以免后面忘记了。
先从单指针说起:
首先我们先纠正一下,我前面一直说“指针”,这样不容易理解,我建议大家包括我自己,下次多在“指针”后面加上“类型”,这样叫:“指针类型”、“指针类型”、“指针类型”。
说白了它就是一个类型,int char float 等也是类型,不过他们是数据类型罢了,那为什么要多出这个指针类型?因为这个类型的变量它存的是内存地址,我们知道内存是由一个个空间组成的,每个空间都有一个地址。而这个地址我们就认为它不是数据类型,而是属于指针类型,(我个人觉得这个指针类型也描述得不够恰当,把它想象成“内存地址类型”吧)。只有指针类型才能存储地址(因为我不是什么专家,这样说可能是错误的,但是对于新手来说,这是最容易理解的);
文字太多上点代码:
int i = 5; int j = 6;
int *p = &i;
注意右边的&i 表示取i 地址的意思,左边定义了一个指针类型p ,int : 跟 i 的数据类型一样,* : 这是指针类型的 关键符号,就和 "int" 符号一样,它只是一个声明的符号、声明的符号,为什么用* 、和 int 、float 这些符号? 这个你得去问C语言发明者。那么这时 我们就定义好了 指针类型变量 p,同时这个p的 值是 i 的地址。
此时我们打印 p、和 *p,他们分别是 :
p: x0fffff... 具体是什么不是我们关注的,我们关注的是它是一个内存地址。
*p: 5.
好关键的地方到了,很多人都不理解为什么*p 不是等于 内存地址。我上面说了 int *p 这是表示 定义一个变量它是int型和指针类型的变量。就像 int const p 这样只是定义p变量它是int型常量类型的而已,仅此而已,它的目的是声明p。
后面的*p 为什么等于5,此时变量p的值是变量i的一个内存地址,如果要取i的值怎么办?那么在p 前面 加* 表示取该变量p存储的地址所指向的值。注意一点,在定义变量p的时候* 表示变量的类型,到后面在指针变量p 前加* 就是表示取值。两种不同的意思。如果这样还不理解,就多看两遍。
下面说下双指针:
int i = 5; int j = 10;
int *p1 = &i; int *p2 = &j;
int **pp = &p1;
上面的代码 p1 的值 是 i 的地址,p2的值 是 j 的地址,这个单指针的知识。
那么这里 int **pp = &p1;我们为什么不用 int *pp = &p1;来取p1的地址呢?因为这是不允许的,c语言规定,定义一个用来存储普通变量内存地址的指针变量需要用单指针变量 即 *表示,定义一个用来存储 指针变量的内存地址需要用双指针类型定义即 **,他们的区别是存储的这个地址是普通变量的地址,还是指针类型变量的地址,如果是指针类型变量的地址就需要用** 来定义。如果你把上面的int *p1 = &i;变成 int **p1 = &i;那么这是编译不过的报错的,同时如果你把 int **pp = &p1;变成 int *pp = &p1;那么这也是编译不过的报错的。
那么**pp、*pp、pp的值分别是啥:
先从 pp说起:我们说过,变量pp前面的一大串东西他们的作用只是声明,两个* 是因为语法要求。所以pp的值就是指针类型变量p1的内存地址;
那么*pp 就表示取pp存储地址的值,而pp指针类型变量的值是p1内存地址,取这个地址的值也就是相当于*p1的值 &i 最终值是 i的内存地址。
最后**pp,因为*pp的值是i 的内存地址,所以多一个* 表示取i内存地址的值,也就是5;
为什么我先从pp说起而不是从**p 说起呢?因为我们很容易被int **pp 这个声明影响,记住pp只是一个变量,前面的一串东西都是声明它的,并没有其他的含意,所以从pp变量开始推算才是正确的。
下面弄点难的:
在上面的基础上我们多加一下代码:
*pp = p2;
那么此时的**p、*pp、pp 的值又是什么?
首先不管怎么样,我们都必须从右往左推算。首先pp 这个指针变量并没有变,所以它的值还是p1 的内存地址。
然后*pp 变了,那么*pp 在之前的值是取p1内存地址的值,*p1 对吧?即i 的地址,现在它变成了 *pp = p2,那么它的值即是 j 的内存地址。
那么我们知道了*pp 的值是j 的内存地址,所以在*pp前面多加一个* 就是取*pp地址所指向的值,就是j 内存地址的值,那就是变量j 10。
不理解多看几遍。要下班了88