1、指针是什么:数据存于内存中,CPU如果要对数据进行处理首先就要找到相对应的数据,就是通过地址来找到的。就像你所在的公寓,你如果要找到你的房间就需要根据门牌号寻找。
在CPU和内存之间有地址线连接,其中在x86环境下是32根 地址线,在64位环境下有64根地址线。每根地址线有两种情况,可以反映2个地址,那么32根能反映2^32种,64根能反映2^64种。
2、指针的内存大小:我们如果要存储指针数据,就需需要足够的内存。在x86环境下要存放2^32次方个数据刚好就是要32bit大小也就是4个字节。在x64环境下要存放2^64种数据所以需要64个bit位,也就是8个字节。
综上32位4字节,64位8字节。
3、如何得到内存的地址和使用内存的地址:这里有两个符号分别是 &取地址符号 *解引用符号
取地址符号顾名思义就是得到其地址,解引用符号是通过地址找到其对应的地址所存储的数据。
两个操作符是进行相反的操作的,所以**&*可以相互抵消**。图中的*p就等价于*&a=a;
4、指针内存都是一样大的问什么还要区分指针类型?
原因出在解引用的环节上,因为每种类型的数据会有不同的大小,需要1个或多个字节来存储全部。计算机读取这些数据不是一下全部读取的,是一个字节一个字节的进读取的。那么读取多少就决定的数据的准确性。所以指针类型是来决定解引用的时候计算机读取字节的长度的。
典型的例子可以看我上篇博客,冒泡排序通过指针类型强制转换来交换两个内存的数据https://blog.csdn.net/2301_80772499/article/details/136420805?spm=1001.2014.3001.5502
5、通过指针来进行内存操作:这里我们从第三点最下面得出的结论:&*可以相互抵消就可以理解到了。
6、指针的作用:我们为什么还要另外搞个指针呢?直接改变量不就完了。
原因一: 在函数的传参这部分。通过我前面讲的函数栈帧的创建和销毁这一篇博客可以知道,新函数的开辟会创建临时变量。如果直接想要对我们main函数里面的数据进行更改的化,通过改掉形参的数据是不可能实现的。形参和main函数传过去的实参完全不是一个东西 。因此我们需要用到指针,通过指针的解引用来找到我们main函数里面的 所以需要处理的变量。
总之就是让各个函数里面的非临时变量够通过临时的指针变量相互联系起来,而我们直接传参是不可能的。
可能有人会说arr为什么不是的,其实我们传入的arr[]实际就是arr的地址。arr本身可以表示其地址,函数也是。
原因二是:有时候我们和计算机对话的时候,例如要求它创建内存,计算机不可能自己创建一个变量给你然后你自己使用,你只能将它的地址储存起来从而找到所要创建的内存对象。
7、指针的加减:
指针加减数字:指针加减数字从内存角度来看:就是指针地址增一个类型单位或者减少一个类型单位,这里的类型单位就是只类型的大小,int 4字节 ,char 1字节等。我们让char类型指针加1就是在原来的地址上加1(char)个字节。如果从变量来看就是跳到它相邻的那个变量的地址去。
指针减指针 :指针减指针就得到了两个变量之间的距离。可以用来求数组长度等。
8、指针存储的对象和对应的解引用:我们容易想到的就是各种类型的变量:float int double long short char,结构体等,解引用也就直接加*就行。
其实还有常数组、常变量也是可以的,例如"1234"就会存储它第一个字符的地址。
还有**数组:**这里有多种存储的方式
首先我们看一维数组,这里我们要理解到 如果有一个数组为arr ,用指针接收arr是接收它的地址,我们令arr=&parr,parr才是最内层级别的。
这里的p实际上指的是**(arr[0]) &parr[0]**也就是第一个元素的地址,我们如果对地址进行++,那么通过数组内存连续存放的原理可以遍历所有的元素。
存储数组的地址,p指向整个数组
这里我们可以这样理解,单个类型我们是*p来接收的,如果是单个类型组成的数组,我们也可以用一个类似数组的样式来接收int(*)[] 这里加()的缘由就是防止*和int结合,这样就是有一个地址(*p)指向[4]。
我们转换一下,&arr=&&parr ,所以p是二级指针。p因为是指向的&arr,那么我们进行一次解引用只会得到&parr,还有一层需要解引用一次才正确。因为&arr是指向整个数组的,那么p+1就是跳过整个数组,跳过之后还是二级的我们依然需要两次解引用。
我们如何通过这个二级指针p来遍历数组呢
这里我们先进行了一次解引用,这次解引用等价于*(p+0),就是不跳过数组,也就是arr首元素的地址。然后我们下面的操作就和普通数组指针解引用一个意思了。也可这样理解,*p等价于*&arr也就是arr。
这里有点二维数组的韵味
再看二维数组:
首先是要清除二维数组名指的是什么:
由上面可知,arr=&&pparr;这样更容易理解一点。
二维指针的解引用:
图中arr首先加一,就是跳到第二行的1234,然后解引用,然后再加2就是访问第三个数据。
这个等价于arr[1][2]。
指向整个二维数组的指针: 因为arr=&&pparr所以类比于上面的数组指针,这里要三次解引用。
还有指针存储函数的地址:那么我们怎么定义指针类型呢?
由我举出的例子可以看出,我们只要把函数的返回值和传入值类型弄上就行了。
函数指针数组:
指针的指针:这里我们用图来解释
指针的指针就是存储指针的地址。
指针数组: 就是将指针用数组储存起来。类比int arr[],指针数组的命名为int *arr[]。那么同理二级指针数组就是int**arr[] 。
有什么用呢?我们知道只要有数组首元素的地址和长度我们就得到了整个数组的数据,那么我们把多个一维数组的首元素地址用指针数组存起来,那么变相的就形成了二维数组 。同理,我们把各个二维数组的首元素的地址存起来,就可以形成三维数组。
指针来实现动态数组:具体看我这篇博客-->动态内存<--
如果有错误请提出宝贵建议!