你真的了解吗?(深入指针,assert,数组名)

一、指针概括

1、指针定义

  Def:  指针(pointer)也就是内存地址(指针==地址)指针变量是用来存放内存地址的变量,在同一CPU下,不同类型的指针变量所占用的存储单元长度是相同的,但所占空间大小由指针变量的类型所决定。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

      一般形式为:类型(int char long short...) * 变量名

       void*为泛指类型,可以用来接收任何类型的地址,但不能直接解引用或位置加减

2、指针运算符

&   取址运算符
   功能:取出变量的内存地址(升一级) 
  取值运算符
(解引用)
   功能:访问指针指向的变量内容(降一级)

3、指针大小

  (a)×86(32位):32个bite位(相当于32个地址总线),占4个字节空间大小,最多占2^32字节空间大小(一个地址线发出两个信号)

(b) ×64(64位):64个bite位(相当于64个地址总线),占8个字节空间大小,最多占2^64字节空间大小(一个地址线发出两个信号)

注:大小与变量类型无关,变量类型只决定指针解引用访问的权限大小和向前向后走的长度

4、const修饰指针(变量不变)

  const放在*的左边限制*p(为p指向空间的内容,p不受限制)【const int * a / int const * a】

  const放在*的右边限制p(为p的地址,*p不受限制)【 int * const a】

5、指针运算

a、指针+/-数字=指针;

b、指针-指针=指针之间元素的个数(数字)【两个指针需要指向同一区域】

c、指针见的关系运算【比大小(地址的高低)】

6、野指针

(1)指针的初始化

通过赋值语句初始化指针变量:int * pa = &a(将a的地址赋值给pa指针变量,*告诉我们pa为指针,int告诉我们pa指向的空间存的数据为int类型,int *告诉我们pa的类型)

(2)野指针的形成

a、定义

  Def:C语言中指针初始化是指给所定义的指针变量赋初值。指针变量在被创建后,如果不被赋值,他的缺省值是随机的,它的指向是不明确的,这样的指针形象地称为“野指针”。野指针是很危险的,容易造成程序出错,且程序本身无法判断指针指向是否合法。 

b、成因

#变量未初始化(局部变量为随机值,全局变量默认为0)

#指针访问越界

c、规避
#可以在指针定义后,赋值NULL空值

也可写成:p=0或p='\0'

这两种形式和p=NULL是等价

举例说明

  上面两行代码的含义是,指针变量p被赋值为空。虽然定义了一个指针变量,但是它并不指向任何存储空间。 

#使用assert断言

包含头文件#include<assert.h>,用于终止错误代码并指出路径

assert的使用

(1)表达式:assert(表达式)【仅在Debug版本使用,release版本不行(Linux系统可以)

(2)可用#define NeDEBUG取消断言

7、简易应用

1、交换两个int类型的值:

a、引入第三变量交换(常用)

b、使用按位异或^进行交换(罕见)

c、传址调用(让函数与主调函数产生联系)

二、二级指针

1、定义:用于存放指针变量的指针变量称为二级指针

   注:第二个*告诉我们pb为指针,int*告诉我们pb所指向的空间存储数据类型为int型指针,int**告诉我们pb的类型为二级指针。

三、指针数组

1、定义:(本质为数组)数组元素为指针变量的数组成为指针数组

2、形式:

int *arr[ ]形式等同于int arr[ ]

四、字符指针

1、定义:用于存放字符(数组)地址的变量成为字符指针(变量)。

p[3]=>"abcdef"[3]=d(%c)

五、数组指针

1、定义:用于存放数组地址的变量成为数组指针(变量)。

六、数组传参

1、数组名相当于数组首元素的地址(一维)

       二维数组数组名相当于第一行即第一个一维数组的的地址

2、数组传参的本质是传数组首元素的地址

arr[i][j]==*(*(arr+i)+j)   *(arr+i)==arr[i]

七、函数指针(数组)

1、定义:函数指针是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。函数指针有两个用途:调用函数和做函数的参数。

                函数指针数组是一个其元素是函数指针的数组。那么也就是说,此数据结构是一个数组,且其元素是一个指向函数入口地址的指针。

2、函数名==&函数名==函数的地址

3、形式:int(*p)(类型)p为函数指针,指向类型为int(*)(类型)

                 int(*p[])(类型)数组存放数据类型为int(*)(类型)p[]为数组

3、应用:

(1)简易

(2)与函数指针数组合作用于实现计算器回调函数

专业术语为转移表( 使用转移表可以替代冗长的switch和if-else语句,分离了具体操作和选择代码,是一种良好的设计方案。和其他指针一样,对函数指针执行间接访问之前,必须把它初始化并指向某一个函数。)

八、小结

   经过这篇文章你是不是对指针有了更深的了解,但指针的使用依旧变化莫测,需要我们不断探索,练习才能感受到其中到奥妙。希望各位可以好好咀嚼这篇文章。原创不易,请点赞并收藏,认真学习哦!

知识学无止境比如给大家推荐两段代码阅读:

1 (*(void (*)())0)();

第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。

第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。

第三步:(*(void(*) ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。

第四步:整体是函数调用。
 

void (*signal( int , void (*)( int )))( int );
第一步:signal为一个函数,函数参数有两个类型int,void(*)(int)用于接收
第二步:void(*)(int)为signal函数返回的函数指针类型
第三步:整体为一个函数声明
    我们还可以使用typedef关键字对类型进行重命名进行上述代码优化,望朋友们读完正文后探索探索。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值