1.指针是什么 ?
指针是什么?
我们知道计算机内存中的基本存储单位是字节,计算机对每个字节都会进行编号,我们把对字节的编号称为地址,那么这个地址也就称为指针
地址:地址是唯一标识一块内存空间的,我们可以通过地址找到对应的内存空间
注:我们通常所说的指针是指的指针变量 ,是用来存放地址的变量。
指针:地址
指针变量:存放地址的变量
内存编号图:
我们如何将变量的地址放入到一个指针变量中?
我们通常用 & (取地址符),将一个变量的地址放入到指针变量中
int a = 0; int* p = &a;
注:a 是 int 类型,所以它占4个字节,将 4个字节中的的第 1 个字节地址放入指针 p 中。指针 p 的类型是int*,但并不代表指针 p 也占4个字节,而是代表着 p 找到了变量 a 的第一个字节的地址后,应该访问多少个字节。
我们现在知道了计算机会对内存中的每一个存储单元(字节)进行编址,那我们现在思考一下计算机是如何对进行编址的?
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0), 那么32根地址线产生的地址就会是: 就会产生2的32次方个地址,每个地址由32位二进制进行编码
同样的方法对64位的机器,就会产生 2 的 64 次方个地址,每个地址由64位二进制进行编码
32位的机器:一个地址由32位二进制组成,8个二进制等于一个字节,那么32位的机器产生的地址也就是4个字节
64位的机器:一个地址由64位二进制组成,8个二进制等于一个字节,那么64位的机器产生的地址也就是8个字节
2.指针变量和指针变量类型
我们知道变量有不同的类型,那么指针变量有没有类型呢?
准确来说:指针变量是有类型的,但它跟变量的类型却有所不同。变量的类型一般大多数是用来开辟多大的空间的,而指针变量的类型并不是用来开辟空间的,而是表示它能访问多大空间
接下来我们一起来看看指针变量类型的作用吧!
2.1指针变量+-整数
变量 a 是一个int类型的,打印 &a 打印的是变量 a 起始位置字节空间的地址,pi 和 pc 里面存放的都是 a 起始位置的地址 ,所以它们打印的也是 a 起始位置的地址。但是 pi 是 int* 类型的所以它可以访问 4 个字节 ,所以pi + 1跳过了四个字节的地址。pc 是char* 类型的所以它可以访问 1 个字节,所以pc + 1跳过了 1 个字节的地址
指针类型决定了指针向前或向后走一步有多大距离
2.2指针变量的解引用
将n的地址强制类型转换为 char* 赋值给 char* pc 字符指针变量。因为每个变量的地址都是起始位置的地址,那么 pc 中也就存放了 n 变量的起始位置的地址,然后给 pc解引用 找到 pc 指向的地址对应的空间,因为 pc 是 char* 类型的它只能访问一个字节的空间大小,所以它只改变了起始位置空间里面的内容。
n 是一个整型变量,将 n 的地址赋值给 int* pi 整型指针变量。因为每个变量的地址都是起始位置的地址,那么 pi 中也就存放了 n 变量的起始位置的地址,然后给 pi解引用 找到 pi 指向的地址对应的空间,因为 pi 是 int* 类型的它可以访问四个字节的空间大小,变量n是整型占四个字节空间大小,所以它改变了n所有的空间里面的内容
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节
3.野指针
野指针:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
3.1野指针的成因
① 指针未初始化
局部变量指针未初始化,默认为随机值 。如果不知道给指针初始化为什么,建议初始化为NULL。
② 指针越界访问
数组下标是从 0 开始的,arr 数组中有 10 个元素,所以下标到 9 就结束了。但它依然可以访问改变下标为 10 的空间里面的内容,这就是越界访问,当程序运行时程序会直接崩溃并提示崩溃原因。当指针指向的范围超出数组 arr 的范围时,p 就是野指针
③ 指针指向的空间释放
用 malloc 开辟一块 int 类型大小的空间,让指针变量 p 指向这块空间。当释放了这块空间时应该让 p 指向 NULL ,要是 p 没有指向 NULL, p 依旧记得这块空间地址。但是这块空间已经释放了也就等于还给了操作系统,那就很可能被其他分配的动态内存所占用。但是 p 还是指向了这块空间,当使用者忘记了前面已经释放这块空间时,就很有可能误改变了已经属于其他空间的值。所以当指针指向一块动态内存开辟的空间时,当这块动态内存被释放,指针应该置为 NULL。
3.2如何避免野指针
指针初始化
小心指针越界
指针指向空间释放即使置NULL
避免返回局部变量的地址
指针使用之前检查有效性