目录
大家好,我-曳渔又来分享了,这一次我要分享的是有关于指针的内容。指针呢是一个大家族,并且很多学习过C语言的都认为指针是非常难的,所以这一次内容会非常的多,让我们来共同攻下这个骨头!!!
一:指针的基本概念
在了解指针概念之前,我们需要先了解关于数据是如何在内存之存储的,其实是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节(相当于8个比特位也就是每个8人寝室的8个人),每一个内存单元都有一个编号(相当于每个宿舍的房门号),这个编号也就相当于指针。
1.地址:
我们来举一个例子:
在这里我们创建了整型变量a,内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址。
上图中4个字节的地址分别是:这里的地址就相当于宿舍的门牌号只要找到了地址就可以找到变量a。所以内存单元的编号=地址=指针。
2.取地址操作符(&)
当我们知道a的地址的之后,我们要如何得到a的地址呢,这里就需要取地址操作符(&)了。
举个例子:
这里会打印0x00D3FB10,因为&a取出的是a所占4个字节中地址较小的字节的地址。虽然整型变量占用4个字节,我们只要知道了第⼀个字节地址,顺藤摸瓜访问到4个字节的数据也是可行的。
3.指针变量:
当我们在&a的地址后得到0x00D3FB10,大多数时候我们都要把他存储起来,来方便我们今后使用,那么我们要把它存储到哪里呢?这里就需要指针变量了。
OK 我们也来举一个例子:
指针变量也是⼀种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址。
这种变量也有很多类型:int*,short*,float*,char*.....等等,可以简称为数据类型*变量名。
可能还有人不是很理解,那么我们来拆分一下int*p,*是说明p是指针变量,而int说明p指向int类型
4.解引用操作符(*)
上面我们说明了地址该如何取出地址并存储,那我们存储后如何使用呢?这里就出现了一个新的操作符(*)。那么我们如何使用呢?下面我们举一个例子:
上面的*p就是就是通过p里面的地址,找到p所指向的空间,*p就是a这个变量。我们也可以通过*p来改变a的值。如:
到这里就会有人问了,我直接改变a的值不好吗,为什么还要多此一举呢?这里就像狂飙里的(很火的)强哥和老莫,强哥为什么杀人找老莫,他自己杀不好吗,因为这样警察就找不到是他。所以这里和上面a和*p的关系是一样滴!!!
5.指针变量的大小:
我们直接举例子:
上面的两张图打印的东西是一样的,但为什么输出的是不一样的呢?
因为:32位平台下地址是32个bit位(即4个字节)(x86)
64位平台下地址是64个bit位(即8个字节)(x64)
所以我们需要注意:指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。
6.指针变量的意义:
由上面可知我们的指针变量的大小是一样的在同平台下,那么就有人问了,指针变量大小都一样我一直用一种指针变量不行吗?那肯定是不可以滴,因为指针变量是存在意义滴,那我们举个例子来说明吧:
这里将(int类型)n的4个字节全部改为0。下面再让我们来看一段代码:
由这两段代码可以知道:指针的类型决定了,解引用时候一次可以操作几个字节。
二.指针运算:
1.指针+-整数:
这里我们直接上代码:
(1):
我们可以看到char*类型+1跳过一个字节,int*类型+1跳过4个字节。
所以指针的类型决定了指针向前或者向后走⼀步有多大距离,指针自增自减是加一或减一。
(2):
我们知道数组的地址是来连序存放的所以我们知道一个地址就可以知道整个数组了。
上代码:
2.指针+-指针
上代码(我们来模拟实现一个strlen(计算字符串长度的,到‘\0’停止)函数):
这里我们可以看到指针—指针的应用。指针加指针也是相似的用法。
3.指针的关系运算:
关系运算可以分为三中:
1):指针之间的大小比较:
2):两个指针是否指向同一个内存单元
3):指针是否为空指针(NULL)
三.野指针:
在我们学习C语言中的指针的时候经常会出现定义野指针的情况,什么是野指针呢?
1.概念:
野指针就是指针指向的位置是不可知的,随机的,不正确的,没有明确限制的。
在我看来野指针就像是一条野狗一样迭谁咬谁。
2.形成原因:
1):指针未初始化:
2):指针越界访问
3):指针指向的空间释放
3.规避:
1):指针初始化
2):小心越界访问
3):当指针变量不使用的时候,及时用NULL。
这样就象是把野狗栓上就不会乱攻击人了。
四.指针中常使用的两个函数:
1. const修饰变量:
2.assert断言
1):概念:assert.h 头文件定义了宏 assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行
#include<assert.h>
assert(p!=NULL);
如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示。
五.二级指针:
1.概念:存放一级指针的变量。
2.使用样例:
六.字符指针:
这里的字符指针a存放的是什么呢?是不是有人认为是”hello word“呢?不,其实不是,其实存放的是首字符的地址。
七:数组指针:
1.概念:数组指针变量是用来存放数组地址的
2.数组指针的结构:
如:int (*p)[10]。
p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个大小为10个整型的数组。所以
p是⼀个指针,指向⼀个数组,叫数组指针。
注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合
3.初始化:
八.函数指针:
1.概念:函数指针变量应该是用来存放函数地址的,未来通过地址能够调用函数的.
2.函数指针的结构:
3.函数指针的使用:
九.函数指针数组:
1.概念:数组是⼀个存放相同类型数据的存储空间,那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组。
2.函数指针数组的结构:
十.练习题:
1.
这个的结果是什么呢?
这是为什么呢?
总结:
OK 指针就介绍到这里,之后的结构体中也有用到指针的地方,那么我们下期再见!!!