目录
1. 指针变量为什么要有类型?
2. 野指针
2.1 未初始化导致的野指针
2.2 指针越界导致的野指针
2.3 如何规避野指针
3. 指针运算
3.1 指针加减整数
3.2 指针减指针
3.3 指针的关系运算
4. 二级指针
5. 指针数组
5.1 如何使用指针数组模拟二维数组
上一期已经解释了指针和指针变量的区别以及含义,这一期我们来具体了解一下指针到底有什么作用。
1. 指针变量为什么要有类型?
我们知道指针变量的大小是根据所在平台决定的,若平台是32位即x86环境,则指针变量是4个字节,若平台是64位,则指针变量是8个字节。既然指针变量不会根据指针类型变化,那么我们为什么要区分指针变量的类型呢?换句话说char* 和 int* 都有能力存储4个字节的地址,为什么不统一成一个自定义的指针变量例如ptr* ?
从上图可以得知,我们把int*类型的地址强行赋给char*类型的地址,再进行取值调用的时候,会根据char*来进行赋值,以至于只会将一个字节赋值成0,若是正常使用int*来接收,那么四个字节都是0 ,如下图所示。
由下图可知,虽然不同指针变量的存储类型不影响地址的存储,但是当直接对地址进行运算,还是会根据指针类型的不同进行运算。char*类型+1,跳过1个字节,int*类型+1,跳过4个字节。
所以我们会得到这样的结论:指针变量的类型在存取地址的时候可有可无,在修改地址指向的内容的时候是非常有必要的,它决定了在利用地址更改值的时候需要更改多少个字节;若直接对地址进行运算,那么会根据指针变量的类型+‘1’,这个‘1’可能是char类型的一个字节,也可能是int类型的四个字节。
使用float*和int*的时候,无论是访问内存还是使用内存,都是4个字节,那么可不可以混用呢?
答案是:不可以。
下图是整型解引用赋值整型,我们可以看到100以16进制存入内存。
我们把100.0存入内存,发现内存存的数据发生了变化, 虽然都是100,但是浮点数存入内存的方式是不同的。
2. 野指针
指针指向的内存没有初始化,或者已经被销毁,此时的指针称为野指针。
2.1 未初始化导致的野指针
2.2 指针越界导致的野指针
2.3 如何规避野指针
①指针初始化。
②指针小心越界。
③指针指向的空间置为NULL。NULL是0,类型是void*,如果取值的话一定会报错(默认0地址不能访问),所以,我们可以先判断这个指针如果不是NULL再进行取值。
④避免返回局部变量的地址,因为局部变量已经被销毁了(没有那块内存空间的使用权限了)。
⑤指针使用之前检查有效性。
3. 指针运算
3.1 指针加减整数
这里的values[N_VALUES]并不算下标越界,因为并没有使用这段内存,只是用了一下这个地址作为判断条件。
3.2 指针减指针
当同类型的地址减去同类型的另外一个地址,得出的结果的绝对值是两个地址之间的元素个数。
需要注意的是,两个指针指向的必须是同一块内存,不然毫无意义。
那么有同学会想,指针+指针得到的结果是什么呢,这个结果毫无意义,类似于你可以把日期相减,得到天数,但是你不能把日期相加,这样就毫无意义。
3.3 指针的关系运算
其实就是地址之间的比较,判断两个地址谁大谁小,从而对地址指向的内容进行操作。
4. 二级指针
简单描述一下,就是指针变量里面存的地址,这个地址是一个指针的地址。乍一听是不是以为在说绕口令呢?下面用一张图来进行诠释。
上图中表示int * pa = &a;我们可以这么理解:*号表明pa的类型是一个指针类型,int表明这个指针类型指向的是int类型;那么我们是不是可以来理解一下二级指针。
int* *ppa = &pa;还是将类型拆开,距离ppa最近的*表明ppa是一个指针,int* 表明ppa指向的类型是int*的类型。
总结:二级指针是用来存放一级指针变量的地址。
5. 指针数组
主语是数组,即存放指针的数组就是指针数组。
5.1 如何使用指针数组模拟二维数组
首先构造出三个一维数组,所谓二维数组就是将这三个一维数组连起来;我们构造一个指针数组,分别存入之前构造的一维数组名,在之前的帖子说明,一维数组名是数组的第一个元素的地址,所以分别存入了三个地址,我们需要遍历指针数组,得到三个一维数组的首地址,再引入一个变量j,根据指针加减法,就可以访问一维数组中除了第一个元素的其他元素的地址,最后解引用就可以得到最后的结果。
#include <stdlib.h>int main()
{int arr1[4] = {1,2,3,4};int arr2[4] = {2,4,6,8};int arr3[4] = {3,6,9,12};
// 用一维数组模拟出二维数组的效果int* arr_sum[3] = {arr1,arr2,arr3};for(int i = 0;i < 3;i++){for(int j = 0;j < 4;j++){printf("%d ",*(arr_sum[i] + j));}printf("\n");}return(0);
}