超超详细的指针讲解

 本篇将先初步介绍指针的各种有关知识,然后再讲解指针与数组、指针与函数等


目录

内存

指针基本有关知识

指针有关操作符:

指针变量的定义: 

指针变量的大小:

指针变量类型的意义:

指针运算:

野指针:

 二级指针:

特殊点的指针类型

数组指针:

函数指针

空指针


首先要清楚一点,指针和内存是不可分割的,所以我们要先对内存有一定了解才能学懂指针。

内存

内存被划分为一个个内存单元,大小取一个字节,我们可以这样理解:把内存看作一个个房间,每个房间都有一个地址编号并且每个房间大小为一个字节

对于编号、地址和指针的关系有:内存单元的编号 == 地址 == 指针

而我们创建一个变量时就是把这个变量放进这个房间(地址)里,而我们指针就是获取这个地址,以对它进行各种操作


指针基本有关知识

首先在正式讲解指针前先将三个注意点

  • 指针变量里放的是地址
  • 指针变量也是变量,拥有自己的地址
  • *p 是 p 指向的空间

指针有关操作符:

&:取地址操作符,创建变量就是向内存申请空间,并放入该空间地址, & 可以取出这个地址的编号

*:解引用操作符,将指针(地址)解开,获得其里面的数据,例:

int a = 10; //创建一个变量 a,并赋值 10
int* p = &a; //取出 a 的地址并给予指针 p
printf("%d", *p) //把指针 p 解开,获得 p 所存的地址中所装的 变量 a,此行就会打印 10

指针变量的定义: 

数据类型 * 指针变量名 

其中“数据类型”是此指针所指向的数据的类型(也就是指针所存的地址里装的变量的类型),指针变量名就是此指针的变量名

例:

int * a //变量名为 a,* 说明这是一个指针,此指针指向的数据的类型为 int
char * b //变量名为 b,* 说明这是一个指针,此指针指向的数据的类型为 char
char (*arr) [10] //变量名为 arr,(*) 说明这是一个指针,此指针指向的数据的类型为 char [10](一个数组,元素为 char 类型,元素个数有十个) 

 注意:指针变量的类型是非常重要的(后面会讲),对于一个指针变量的类型,我们可以这样理解:如上例子:变量 a 的类型为 int*,变量 b 的类型为 char* ,变量 arr 的类型为 char [*] [10],指针变量与其他变量没有区别,只不过类型是 int*、char* 等


指针变量的大小:

因为指针就是地址,所以指针的大小就是地址的大小,在 32 位机器中地址有 32 个比特位,一共就是 4 个字节的空间,同理 64 位机器 8 个字节


指针变量类型的意义:

指针所存的都是地址,可指针的类型与其的使用有莫大的关系

1.指针类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节),指针所指向数据类型有多大,一次操作时就操作多少字节,例:

                                         如果不了解大小端存储模式,请点击我 

 2.指针的类型决定了指针向前向后走一步有多大距离(偏移量),这个知识和指针的整数加减运算有关,举个例子:

注意: 图中我箭头所指是以空间开头为准,如果箭头指向空间中央也是表示指向这个空间,这个看个人习惯理解


指针运算:

1.指针加减整数 :指针加减几,就向右(+)/左(-)偏移 指针所指数据类型大小 * 加减的数字,例:int* p1 + 1 表示地址向右偏移 4 个字节,char* p2 - 3 表示地址向左偏移 3 个字节

2.指针减指针:指针减指针的运算结果的绝对值为两指针间相差的元素个数(此运算方式如同天数的运算,1 日到 5 日相差 4 天,从 1 日开始到 4 日结束(5 日开始))

注意:此运算只能在同一块空间使用

例:

int arr[10] = { 0 };  //创建一个整型数组
arr + 1 - &arr + 1 = -10; //arr 表示数组第二个元素地址,&arr + 1 表示跳过这整个数组后的地址,中间差了 9 个元素,并且 arr 地址比 &arr + 1 地址小,所以为 -9
//arr 和 &arr 的区别将会在指针数组中讲到

 3.指针的关系运算:只有两个指向同一数组的指针才可以比较,比较的是地址的前后,若是两个无关的指针比较一般编译不通过


野指针:

 野指针就是指针不知道指哪去了,指向随机地方,指向不可访问区域等指针

成因:1.指针未初始化 2. 指针越界访问 3.指针指向的空间被释放 等等

规避方法:

1.指针初始化,若有需要直接指向的地址则直接指向其初始化,若不知道指向哪则可以给指针赋值 NULL ,NULL 是C语言中定义的一个标识常量符,值为 0 ,该地址无法使用,避免误用出现野指针

2.小心越界访问:注意自己的程序向内存申请了哪些空间,避免指针访问超出空间

3.指针变量不再使用时,及时置NULL,并在再次使用前检查其有效性,这样可以避免指针的误用和错用

4.避免返回局部变量的地址,若要返回局部变量的地址可以使用 static 使变量暂时不被销毁


 二级指针:

 指向指针变量的指针,因为所指的类型为 int* ,所以二级指针的类型为 int* * (后面一个 * 表示这是一个指针,int* 表示这个指针所指的数据的类型为int* ),同理三级指针类型 int** *(三级指针都已经很少用)

其原理是指针也是变量也拥有自己的地址,不过它所存的数据也是地址,二级指针就是存的这个指针变量它自己的地址


特殊点的指针类型

接下来将会讲三个东西:数组指针,函数指针,空指针 ,其实这些指针类型没什么特殊的,只是比整型指针、字符指针等指针多一两个需要知道的知识点、然后类型看起来要复杂一点

数组指针:

 声明:type (*name) [num],其中 type 为指针指向的数组的元素的类型,num为数组元素个数,指针类型为 type (*) [num]

注意数组指针和指针数组的区别,数组指针是指向数组的指针,是指针,指针数组是元素为指针的数组,是数组。例:int *arr [10] 和 int (*arr) [10],若没有 () 则 arr 先和 [10] 组合,即数组,若有 () 则 arr 先和 * 组合,即指针

数组还有一个知识点必须知道,那就是数组名的在不同情况下的含义

一般情况下数组名就是数组首元素的地址,但有两个例外:

1. sizeof(数组名),sizeof 中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小

2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址,地址值是首元素地址的值,但类型为这个数组的类型

像前面举的一个例子,arr + 1 和 &arr + 1 的不同的原因就是如此,arr 是首元素地址,指针类型为 int*,&arr 是整个数组的地址,指针类型为int(*)[10],但他们当中存的地址是一样的,不过类型不同导致解引用时效果不同


函数指针

声明 :type (*name) (type1, type2),其中 type 为指针指向的函数的返回类型,(type1,type2)为指针指向的函数的参数类型,指针类型为 type (*) (type1, type2)

要注意 函数名 和 &函数名 都表示函数的地址,两种写法的效果是一样的


空指针

声明: void* name

空指针可以接受任意类型的地址,但不能直接进行指针的 +- 整数和解引用的运算

空指针一般是当不确定会传过来什么类型的指针时,用来接收其地址的


到这里,本篇的指针讲解就结束了,其包含很多理性知识,大家一定要多多使用才能彻底将其消化理解

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值