目录:
一、内存和地址
二、指针变量与地址
三、指针变量的类型的意义
四、指针运算
五、野指针
正文:
一、内存和地址
我们知道计算机在处理数据时,需要的数据是在内存中读取的,处理后的数据也会放回内存,那么如何有效的管理内存空间呢?
实际上内存被划分为一个一个的内存单元,每个内存单元的大小为一个字节。
每个内存单元也有各自的编号,根据内存编号,有了这个编号,CPU就能快速的找到相应的内存空间。
生活中的门牌号,我们可以理解为地址,所以计算机中的内存单元的编号我们也称为地址,C语言又给这个地址取了一个新的名字叫指针。
所以,我们可以认为 内存单元的编号==地址==指针。
二、指针变量与地址
2.1取地址操作符&
了解了内存与地址的关系,那么我们接下来了解一下指针变量。
根据前面的知识,创建变量实际上就是向内存申请开辟一块空间,那么我们如何知道我们申请的是哪块空间呢?
这里我们就需要了解一下取地址操作符 &
(上图与下图不是一次调试过程)
我们可以看到&a取出了整型变量a四个字节中较小的那个地址,只要知道了第⼀个字节地址4个字节的地址都被我们看到了。
2.2指针变量与解引用操作符 *
2.2.1指针变量
之前我们通过取地址操作符找到了整型a的地址,这个地址也是一个数值(0099FC8)得到了这个地址我们是不是也有必要将其也存储起来方便我们日后使用?
存储地址的变量我们将其称之为指针变量。
int *p =&a的意思是,取出a的地址将其存储到指针变量p中
指针变量就是用来存放地址的变量,存放在指针变量中的值都会被理解为地址。
2.2.2如何理解指针类型
我们看到上图中的变量p是int*类型的变量,那我们如何理解呢?
实际上,*代表变量p是一个指针,int代表了p指向的是一个int类型的变量。
那么char类型的又如何表示呢?
2.2.3指针变量的地址
这里我们提一嘴,指针变量内存的是它指向的对象的地址,那么指针变量也是变量,它是不是也有地址呢?
我们看到指针变量确实也是有地址的。
也就是说,指针变量的地址内放了它指向的对象的地址,通过解引用操作符*找到该地址,而这个地址内存了变量a的值。
2.2.4解引用操作符 *
前面提到指针变量的地址时我们其实就在使用*,那么如何理解*的作用呢?
我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)
指向的对象,而想要拿到地址中存到的东西,就需要解引用操作符*了。
*p的意思就是通过p中存放的地址,找到指向的空间,*p其实就是a变量了;所以*p=5,这个操作是把a改成了5.
2.2.5指针变量的大小
在《计算机组成原理》中我们知道,32位的计算机有32位的地址总线,每根地址线都可以表现1或0的电信号,那我们把32根地址线产生的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4个字节才能存储。
因为指针变量是存放地址的,因此,32位的机器上指针变量的大小为4个字节。
我们看到,在x86的环境下,无论是指向什么类型对象的变量,他们的大小均为4字节
同理,64位的机器上有64根地址总线,⼀个地址就是64个bit位,需要8个字节才能存储。
所以64位环境下,指针变量的大小为8字节
32位平台下地址是32个bit位,指针变量⼤⼩是4个字节,64位平台下地址是64个bit位,指针变量大小是8个字节。指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。
三、指针变量的类型的意义
指针变量类型的不同带来的是解引用时权限的不同,即一次能操作几个字节(int *类型解引用一次能访问4个字节,char*类型解引用一次能访问1个字节)。
指针变量的类型也决定了指针一次能越过多大的距离。
我们可以看到char*类型+1一次越过1个字节,int*类型一次越过4个字节。
四、指针与数组之间小的联系
因为数组在内存中是连续存放的,我们找到数组的首元素的地址,也能找到数组的所有元素。
那么指针是否也能达到这个效果呢?
我们看到二者结果是一样的,那为什么呢?我们接着打印
发现三种打印方式是一样的,那么arr[i]=*(arr+i)==*(p+i)。
那么是不是arr[i]实际上就是首元素的地址 越过i个整数的字节 所到达的下标的地址 然后进行解引用 得到该地址内部所存的元素。所以arr[i]只是一种表达方式,换成i[arr]也可以达到想要的效果。
五、野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。这样的指针是极其危险的。
那么为什么会出现野指针呢?
1、指针未初始化,指针默认为随机值。
2、指针越界访问,当指针指向的范围超出数组arr的范围时,p就是野指针。
3、指针指向的空间释放
如何避免野指针呢?
1、指针要初始化
如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL.NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址会报错。
2、小心指针越界
一个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。
3、指针变量不再使用时,及时置NULL,指针使用之前检查有效性
对于指针,在使用之前,我们也要判断是否为NULL,如果是不能直接使用,如果不是我们再去使用。