指针篇(1)
首先让我们来深入了解一下这个指针
1. 何为指针
何为指针,指针是C语言中的重要概念,它是一个变量(可以被修改的就是变量),用来存储地址,而它存储的就是另一个变量的地址,我们可以通过指针来访问或直接修改另一个变量的值,指针的定义方法是在变量前面加上个 * 号 ,例如 int*p
2. 内存和地址
当我们初步知道了指针的作用后,如果想要继续深入了解指针,就必须知道“内存和地址之间的关系”。
2.1 内存
首先,内存就相当于我们生活中的宿舍楼,比如说这个宿舍楼的房间很多,足足有一百多间,如果有朋友想要来找我玩(深入交流),怎么让他快速又高效的找到我所在的宿舍呢?很简单,就是给每个宿舍安排上一个编号,也就是门牌号,这样就可以快速且高效的找到我所在的宿舍。
那么,在计算机上其实也差不多,计算机cpu(中央处理器)在处理数据时,是从内存中读取的,处理完后又放在内存里面,那这些内存是如何高效的管理的呢???其实就是把内存分为一个个的内存单元,每个内存单元为1个字节,1个字节为八个bit位
这就相当于八个人的宿舍,一个bit位代表一个人,而每个内存单元都有编号(这个编号相当于宿舍的门牌号),用于去访问宿舍的任意一位学生,有了这个编号,CPU可以快速找到这个内存空间。在生活中我们把门牌号叫做地址,在计算机中我们把内存单元的编号也叫做地址。
在C语言中,给了地址一个新的名字叫 :“指针”
所以我们可以理解为 : 内存编号 == 地址 == 指针
(注 : 这里并不是说一个字节只有一个地址,而是每一个bit位都有自己的地址)
2.2 内存和地址之间的联系
当CPU访问内存中的数据时,必须知道这个数据存在于什么位置,这里我们就可以用 “&” 取地址操作符,取出变量的地址,从而查看这块空间中的情况。
得到的是这个地址,那么让我们来调试一下,看看a是不是在这个地址(0a = 10,所以a变量就储存在这块空间里)
这里我们可以看到,a确实是在这个地址(调试这里的0x00B3F930,前面的0x指的是16进制),因为是int类型的,所以存放了四个字节(地址旁边的 0a 00 00 00 各代表一个字节)。
这里就有人要疑惑了,不是说1个字节有8个bit位吗?怎么这里只有两个,剩下的6个bit位呢?别着急,这里我们就要涉及到一个知识点,不管是什么类型的变量在内存中都是以二进制补码的形式储存的(这里我们先不用管补码,后面会讲到),而我们在调试时是以十六进制的形式展示的,所以当我们把十六进制转换成二进制,得到的就是8个bit位
这里有个小知识要补充: 每次创建变量时,都会重新向内存申请一块空间,所以a的每次地址是不相同的~
那这里的a是一个int类型,int类型是 4 个字节,每个字节都有自己的地址,也就是说a变量中存有4个地址,那我们怎么知道取的是第几个地址呢?很简单,上图!
创建一个变量时,变量会向内存申请一块空间,而内存会对那块空间进行编址(单位是字节),所以这块空间的地址肯定是连续的,当我们&时,得到的就是4个字节中地址最小的字节的地址,也就是0x006FFD70,当我们找到第一个字节的地址后,可以顺藤摸瓜的访问到另外三个字节的地址。
当我们去访问时,可以通过这个取地址(&)去访问这块空间,那我们找到这块空间后怎么通过地址去修改变量中的值呢???比如说把a = 10 的值改成 20 ,怎么做呢,很简单,用指针变量去修改。
3. 指针变量
3.1 指针变量的初步认识
指针变量是什么?指针变量也是一种变量,就是指通过地址去修改变量的值,指针变量的定义方法就是int*p(这里的p可以改成自己想改的名字)
那怎么去使用这个指针变量呢???上一段简单的代码来解释:
这里我们创建了个变量a = 10 ,我想把a的值进行修改,所以创建了个int*p(指针变量),把a的地址给了指针变量,用指针去访问并修改 a 的地址,看看打印结果:
输出的是 20,这就是指针变量的作用。
这里有人可能会问,a既然是变量,那给a再赋值上20不就好了,还要创个指针变量,这不是脱裤子放屁,多此一举吗???这里我们换个角度思考,a总有不方便的时候吧,当我们把a的地址给了p之后,代码的灵活性就会大大提高,后期就会慢慢理解了。
3.2 如何拆解指针变量
上面我们介绍到了指针类型的运用方法、那怎么去理解拆开理解指针变量呢?
指针变量 : int * p
这里我们看到p左边的类型是 int * 、指针变量中的*表示这个变量p是指针类型、前面的int则表示p指向的对象、是int类型的,这里我们引用上面的代码来解释一下:
如果想要存放一个char类型的地址,应该存放在哪一个类型的指针变量呢?
答案是 : char*p,以此类推.......
3.2 解引用操作符(*)
指针类型的拆解理解了之后,让我们顺着上面的代码往下看
这里我们看到,当我们把a的地址交给 p后,就可以通过p去修改a变量的内容,那怎么去理解 * p 呢?这里就涉及到了一个操作符 ,叫做解引用操作符(*);
前面我们讲到,p 里面存放的是a的地址,而不是a变量的值,所以要怎么才能获得a变量的值呢???聪明,就是解引用,p里存放着a的地址,当 * 对p 解引用时,就是对a进行更深入的了解,深入到里面存放了什么的地步(这么讲应该能理解吧),所以得到的就是a变量的值。
那*p就是把a解引用之后对a的值进行修改,所以输出结果为 20;
看到这里,可能有人会有一些想法,比如说,当我把a的地址存进p里面后,我把 *p = 20 换成 p = 0 ,把a改成0 ,这时候a里面的值有没有被改变呢?
答案是 并没有,因为p = 0只是改变了地址,当没有对指针变量p进行解引用,就没有办法得到a的值,并对其修改,那a的地址有没有被改成0 呢?
答案还是没有,原因很简单,p里面装的确实是a的地址,那为什么这里a的地址没有改变呢?还是一样的原因,当你没有对p进行解引用,就得不到a的地址,也得不到a的值。那这里p=0,改变的是什么?其实是改变了p本身的地址
同时也是给p赋了一个值
因此可以得出,指针变量也有地址,不是说指针变量是存放地址的,所以它本身没有地址,我们可以打印看看p到底有没有地址
总结 : 1. 当我们没有对p解引用时,就没有办法访问a的地址和它里面的值,更没有办法去修改
2. 指针变量也是有地址的
3. 当我们没有解引用时,p = 0 改变的就是它自身的地址,也是给自己赋值为零
好的,到这里指针篇(1)也就到此结束了,下一篇再见!!!