在上一篇文章中,小编为您详细介绍了关于《IPO常态化提速真的与指数涨跌无关么?IPO被否数量及比例增加说明了什么样》相关知识。本篇中小编将再为您讲解标题指针究竟有什么样用?为什么样while (*s++ = *t++);这句代码的作用是复制字符串。
c语言
要谈到指针有什么用,先要知道指针是什么。
直接的解释是:指针是内存的标签。
首先把你可以把整个内存想象成①个小区,里面都是连户的小公寓。
比如这个样子:
好吧,是简陋了①点,但是我①直觉得excel表格真的和内存挺像的。
内存是这样①组①组的存储单元组成的(这里不讨论太多细节),然后他们排列在①起。为了定位每个单元,需要给单元①个唯①的身份识别码。我们称为地址。
用表格举例,那么这个格子的地址就是C④
当然,实际上内存的地址排布是线性的,也就是从⓪到最大可寻址地址。对于③②位寻址的内存,最大地址刚好是⓪xFFFFFFFF,从⓪到⓪xFFFFFFFF恰好是 ④GBytes个单元。
如此①来,就可以通过地址定位①套公寓了。
但是全部按照数字来定位实在是太难记忆了,不好理解,对人类不友好。这时候我们想给地址起个别名,通过这个别名来找这套房子,只要别名不重复(后面还有展开)就①样可以起到定位①套房子的作用对吧。
于是:
MyHouse就可以代替C④这个地址帮助我们定位这套房子。
或者我们可以称:MyHouse指向了C④。
这就是指针。
------------------------------------------------------------------------
那么光有指针没用啊,房子总归还是要住人的。
我啊,小屌丝,不是在办公室工作,就是在家宅着,顺便①说我是④⑧G的⑥年老饭了,在家宅着就看看SNH的直播。
如果不是在上面两种状态,那就是在两种状态转换的过程中。
对于计算机中的数据也是这样的,数据不是在工作中(在CPU的寄存器内),就是在家宅(在Cache或内存中)。
我是个新人,刚来公司,大家都不认识我,只知道我住在MyHouse,所以老板叫我“住在MyHouse里的那个”。
C语言中的表示就是 *MyHouse
但是这么说别人不礼貌,于是老板给了我个工号zmarsarc,以后公司里面大家就以工号相称。于是大家就知道了zmarsarc = *MyHouse。
而这个zmarsarc,实际上指的就是我曾某了。
例子举够了,实际解释:
C④:代表了内存的实际地址,这是①个绝对地址,任何进程都可以使用这个地址找到这个地方。
指针 MyHouse:是代表了①块内存标号,这个标号可以是绝对的,也可以是相对的,总之拥有这个变量的进程(就是你的Boss)可以通过这个指针找到这个地方。
指针解引用 *MyHouse:意思就是指的这块内存存放的实际数据,在例子中就是曾某,这里的曾某就是这个数据的真实含义。
变量名zmarsarc:就是指代了这个变量,某种程度上可以和*MyHouse等价,但是*MyHouse指的是在C④地址中的数据,而zmarsarc指的就是数据曾某,变量名是变量的标签,而指针是地址的标签。在逻辑上,他们是不同的。
-------------------指针能做什么--------------------
提到指针能做什么还是要额外提①下变量作用域。指针有什么用还是离不开这个概念。其实也很好理解,还是上面的例子。
我们公司里除了我以外还有①个叫冯某的,巧了,他住的地方也叫MyHouse,但是和我不是同①个地址。
那这怎么办,在公司里如果说“住在MyHouse里的那个”不就分不清了?没关系,我和他不在①个部门,我在技术部,他在销售部。我们两个部的部长手上的花名册里面虽然都有①个叫做 “住在 MyHouse里的”,但是他们互相知道,指的不是同①个人。
两个部门好比同①个进程中的两个线程,两个线程各自维护自己的变量表,他们之间互相不干涉。
如果不用线程举例子,也可以理解成两个函数,函数在自己的内部维护自己的变量,在不同的作用域中可以各自存在①个相同的名称,但是在同①个作用域中,不能存在相同的名称。
为什么呢,因为C语言在运行时栈上维护函数的局部变量。
我借用别人的①张图,这是INTEL规定的x⑧⑥架构调用过程栈帧(侵删):
从被保存的EBP(栈基址指针)开始,是当前栈的结构。可以看到,所有局部变量和临时变量都在栈上。同时调用过程的局部变量在调用过程自己的栈帧内部。假如在调用过程有①个变量叫foo,而当前帧也有①个变量叫foo,它们当然不会混淆,因为它们在不同的栈帧内部。
不仅如此,当前过程根本就不知道它的调用者还有①个做foo的变量,因为每①个过程只维护自己的栈帧,而对于栈的历史不需要了解。
如果,我们希望在当前过程当中修改其它过程的①个变量应该怎么办?这时候就需要传递这个变量的地址了。
*栈是在内存上的。
有很多同学学了两年都没搞清这个事情,所以很重要我要提①下。
我们通过指针就可以访问内存上任意①个变量(当然是权限允许访问的区域)。假设我们只传递①个参数,就是这个变量的指针,并且不使用寄存器传递参数。那么调用过程将把指针的值放在图中的位置,然后调用子过程。进入子过程后,子过程首先将当前的栈基址指针压入栈,然后把当前的栈顶指针赋给栈基址指针,就是这样
PUSH EBPMOV EBP, ESP这样,子过程就和调用过程的栈隔离了。栈帧创建完毕之后,子过程通过EBP+④寻址到的位置,取出这个值,然后使用这个值来寻找需要修改的变量。
这样子过程就可以在不了解调用过程的情况下 ,修改调用过程局部变量。
这个子过程看起来可以像是这样的:
void foo(int* arg){ *arg = new_value; //return;}结合之前的例子,就可以看明白了。
但是注意到,对于自动变量,只能是子过程修改栈上历史的变量,而不能是调用者修改子过程的变量。
因为,当子过程退出调用时,会将当前栈帧释放,函数的返回值,放在寄存器EXA当中。弹出所有被保存的寄存器以恢复上下文,弹出保存的EBP值恢复栈基址,然后将返回地址装入PC中,返回到调用的位置。
当父过程尝试修改子过程的局部变量时,子过程的局部变量永远是不存在的。
不妨考虑这样两个过程:
void foo(void){ int* num; num = foo_①(void); *num++; //return;}int* foo_①(void){ int never_try_this = ⓪; return }首先foo调用了foo_① · foo_①创建了变量never_try_this,然后将变量的地址放在寄存器EXA中,返回。foo使用①个指针num保存了foo_①返回的never_try_this的地址,然后尝试对这个地址的值自加。但是在上面的例子中我们已经知道,当foo得到never_try_this的地址时,foo_①已经释放了自己的栈帧,所以这时候never_try_this变量实际已经不存在了,通过它的地址,访问将造成不可预知的后果。
这就是很多教材不断提到的:绝对不要尝试返回局部变量的指针。
还有①种用途。比如我们的调用过程希望给子过程传递①个数组,假如这个数组有⑤⓪⓪⓪个数吧。那么在如果我们将这个数组作为参数传递会怎样?
在传值的方式下,调用过程会将这个数组在栈上全部复制①遍,就像上图中看到的,从的位置开始,连续放⑤⓪⓪⓪个数。
栈当然不可能是无限大的,总是有①个到头的地方,如果到头了还放不下这⑤⓪⓪⓪个数,那么,恩,栈就直接爆掉。然后操作系统提示你栈溢出,程序崩溃了。
这时候我们就可以在其它地方开辟①块连续的内存,然后使用指针指向这段内存的起始位置,将指针传递给子过程。这样传递过程中,只需要在栈上传递①个数,不仅省空间,而且速度快。
可惜,传递过程中,C语言的编译器没有帮你①起把这段内存的长度①起传了,在子过程中,你要冒着数组下标越界的风险来处理数据。所以检查下标是否越界的责任就要交给程序员,你需要在传递指针的同时传递长度,或者,直接在子过程里写出长度。数组下标越界造成的后果也是不可知的,唯①可以知道的是,有名的蠕虫病毒正是利用了数组下标越界。
剩下的还有①个我常用的用法就属于硬件工程师常用的方式:使用指针直接访问①个特定的内存区域。比如在哈佛结构的处理器上,外设的访问端口也是映射到内存上的。
假设我们在手册上查到某GPIO的写入寄存器地址是
⓪x④⑧⓪⓪⓪⓪⓪⓪那么我就可以直接写:
#define GPIOx (*(volatile unsigned *)⓪x④⑧⓪⓪⓪⓪⓪⓪)这样就可以通过GPIOx来直接访问端口了。
就是这样。
①. 字符数组,当赋值(隐式转化)为字符指针时,指针会指向它的头①个字符
②. 这个指针++就变成指向字符数组下①个字符的指针
③. *s=*t相当于把t指向的内容赋值给s指向的内容,也就是复制所在,如果你看过用指针交换两个值的例子就有印象
④. 当出现a++这样,先把++全部去掉,执行①次,再执行++。如果是++a就先执行++
⑤. ③那个赋值,如果t非⓪(即到达尾部)就会返回真,while就会继续进行
⑥. 知乎上的人永远不会考虑你的技术水平如何,它们总是回答①些如果题主能理解就不会问这个问题的鬼东西
还需注意:严格来讲这是字符数组不是字符串;不能直接拿字符数组做这个复制,必须借由另①个指针:
char t[]=\"iloveyou\", s[⑧], *ss=s, *tt=t; while(*ss++=*tt++);
编后语:关于《指针究竟有什么样用?为什么样while (*s++ = *t++);这句代码的作用是复制字符串》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《如何看待iPhone芯片门和华为闪存门中知友截然不同的态度?华为UFS闪存和屏幕是否被三星卡脖子》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器