一篇文章让你搞懂字符指针 数组指针 指针数组 数组传参和指针传参 函数指针
回顾 首先我们来大概回顾一下指针初阶的知识 内存会划分为一个个的内存单,每个内存单都有一个独立的编号—编号也被称为地址,地址在C语言中也被称为指针,指针(地址)需要存储起来—存储到变量中,这个变量就被称为指针变量 例如: 指针的大小固定是4/8个字节(32位/64位平台) 地址是物理的电线上产生 电信号转化为数字信号 32位机器—32根地址线—1/0 32个0/1组成的二进制序列,把这个二进制序列就作为地址,32个bit位才能存储这个地址 也就是需要4个字节才能存储 所以指针变量的大小就是4个字节 同理在64位机器上,地址的大小是64个0/1组成的二进制序列,需要64个bit位存储,也就是8个字节,所以指针变量的大小就是8个字节 1 字符指针 在指针的类型中我们知道有一种指针类型为字符指针char* 一般使用 现在有以下代码 这里本质上是把字符串首字符的a地址放在p当中,相当于p指向了字符串首素a的地址//这个字符串是一个常量字符串,常量字符串不能被修改,所以我们需要加上一个const防止被修改,另外注意一下const的用法,const放在的左边限制的是p,const放在*右边限制的p 我们来将上面的代码打印出来看一看效果
大家思考一个问题(注意结合上述字符指针的知识),看下面代码 代码 const char* pstr = “hello bit.”,本质是把字符串 hello bit. 首字符的地址放到了pstr中
上面代码的意思是把一个常量字符串的首字符 h 的地址存放到指针变量pstr中 掌握了字符指针的基本知识过后我们来看一道笔试题,看下面代码
2 指针数组 整型数组—存放整型的数组 字符数组—存放字符的数组 指针数组—存放指针的数组 这里我们再复习一下,下面的指针数组分别是什么意思 我们来使用指针数组模拟实现一个二维数组 这里的*(*(arr + i) + j)意思是,arr这个指针变量里面存放的是首素的地址,也就是arr1数组名第一个素的地址,然后+依次遍历二维数组,我这里加的一个Sleep(1000)的意思是停留1秒钟打印一个数组 这不是真正的二维数组,真正的二维数组在内存中是连续存放的 3 数组指针 3.1 数组指针的定义 数组指针 类比: 整型指针—指向整型变量的指针,存放整型变量的地址的指针变量 字符指针—指向字符变量的指针,存放字符变量的地址的指针变量 数组指针—指向数组的指针,存放的是数组的地址的指针变量 我们已经熟悉: 整形指针: int * pint; 能够指向整形数据的指针 浮点型指针: float * pf; 能够指向浮点型数据的指针 那数组指针应该是:能够指向数组的指针 下面代码哪个是数组指针? 解释 3.2 &数组名VS数组名 这里我们把数组名的理解讲一下 数组名是数组首素的地址 但是数组名表示首素的地址有两个例外 1.sizeof(数组名),这里的数组名表示的不是数组首素的地址,数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节 2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址 除此之外,所有的其他地方的数组名都是数组的首素的地址 这里有一个现象,大家看下面代码 这里打印的地址都是一样的,但是本质上真的是一样的吗? 我们将代码调试起来看一看
这里虽然我们看到的地址是一样的,但是他们的类型有所差距 这里取地址arr的类型应该是int(*)【10】 正因为他们的类型不同 现在我们来看下面代码 你拷贝这串代码编译运行会发现各自加1的效果产生了不同的效果
原因是指针类型的不同带来的不同效果 对于数组名来说 &数组名得到的是数组的地址 3.3 数组指针的使用 这里的int*p1=&arr可能会报警告,因为指针类型不符合,上面我们给大家介绍了&arr的指针类型是int(*p1)[10] 那么数组指针怎么使用呢?一般放在二维数组上才方便 看下面代码 这里给大家解释一下*(*p+i)+j),加i相当于拿到某一行的地址,然后加j在进行遍历 二维数组的每一行可以理解为二维数组的一个素,每一行又是一个一维数组,所以二维数组其实是一维数组的数组 二维数组的数组名也是数组名,数组名就是首素的地址,arr—首素的地址—第一行的地址—一维数组的地址—数组的地址
一维数组传参,形参的部分可以是数组,也可以是指针 我们看下面代码 形参部分可以写成数组,但是本质上是一个指针,所以建议用一个指针来接收 二维数组传参。形参部分可以是数组,也可以是指针 数组指针—是指针—是指向数组的指针 指针数组—是数组—是存放指针的数组 大家可以用好孩子这个例子去理解一下 4数组传参 指针传参 在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢? 4.1 一维数组传参 第一个OK,数组传参用一个数组接收没毛病 第二个OK,只是把素个数写出来了 第三种OK,用一个指针接收 第四种OK,一个数组20个素,每个素为int*,用int*arr[20]接收没毛病 第五种OK,一级指针的地址用一个二级指针来接收,所以也没毛病 4.2 二维数组传参 第一种OK 形参部分,行可以省略,但是列不能省略 总结:二维数组传参,函数形参的设计只能省略第一个[]的数字 因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少素 这样才方便运算 所以第二种不OK,第三种OK 第四种,数组名是首素的地址—二维数组是一行的地址,绝对不是某一个的地址,所以错误 第五种不行,因为我传过去的是数组名,这里的形参只是个指针数组,那肯定不行,要么写成数组指针或者二维数组 第六种OK,是一个数组指针,可以指向一行 第七种错误,数组名表示首素的地址,第一行的地址怎么可能会用二级指针来接收呢,肯定不对! 4.3 一级指针传参 大家自行理解一下,比较简单 这里大家思考一个问题 当一个函数的参数部分为一级指针的时候,函数能接收什么参数? 比如
4.4 二级指针传参 思考: 当函数的参数为二级指针的时候,可以接收什么参数?
5函数指针 函数指针—指向函数的指针 数组指针—指向数组的指针 举个例子,看代码 结果是一模一样的,你们可以在自己的编译器上面去试一试 函数名是函数的地址 &函数名也是函数的地址 来看一段代码 输出的结果
看下面代码 注意*要先和pf结合称为一个指针,再和参数类型结合组合称为函数指针 来看看下面两段有趣的代码 我们先看第一个 很多人看第一眼我去直接懵逼了,这个0是个什么东西,一个函数指针的相关知识搞这么复杂,其实这行代码是有他的特定意思的,我给大家解释一下 0可以默认为是整型 我可以把0认为是int类型,和x0012ff40没有区别各位 也可以0x0012ff40—是一个以16进制表示的整数 你也可以认为这个东西是地址—地址是编号—可以是整型的地址—Int 举个例子 //void(*p)()—p是函数指针 //void(*)()是函数指针类型 我在0前面加了有个括号 这里是把0强制类型转化为下面这种 void(*)()这种指针类型 所以这行代码的意思是调用0地址处的函数,将0强制类型转化为 void(*)()类型的函数指针 然后调用0地址处的这个函数 这里面就运用到了函数指针的知识,尝试着去理解一下,这行代码出自于C陷阱与缺陷 来看第二个代码 signal是一个函数声明 signal函数有两个参数,第一个参数的类型是Int,第二个参数类型是void(*)(int)函数指针类型 该函数指针指向的函数有一个Int类型的参数,返回类型为void signal函数的返回类型也是void(*)(int)函数指针类型,该函数指针指向的函数有一个int类型的参数,返回类型为void 这个代码有点复杂,我们稍作修改 我们需要了解一下typedef这个函数—类型重命名
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/49842.html