当前位置: 首页 > news >正文

成交型网站建设网站营运费

成交型网站建设,网站营运费,wordpress验证邮箱验证码,福州百度快照优化文章目录问题代码段1 —— 阶乘之和问题代码段2 —— 越界的危害① 发现问题② 分析问题③ 思考问题【⭐堆栈原理⭐】④ 解决问题【DeBug与Release】#x1f468;程序员与测试人员#x1f469;✒总结与提炼问题代码段1 —— 阶乘之和 先来看一道C语言中比较基础的题目#x… 文章目录问题代码段1 —— 阶乘之和问题代码段2 —— 越界的危害① 发现问题② 分析问题③ 思考问题【⭐堆栈原理⭐】④ 解决问题【DeBug与Release】程序员与测试人员✒总结与提炼问题代码段1 —— 阶乘之和 先来看一道C语言中比较基础的题目求解阶乘的和通过调试来观察为何会出现问题如觉得已经会了的读者可以直接看第二道题 先上代码。逻辑很简答首先输入n表示表示n个阶乘之和然后在内部循环中求出每一个数的阶乘计算所得进行累加最后便有了【阶乘之和】 int main() {int sum 0; //保存最终结果int n 0;int ret 1; //保存n的阶乘scanf(%d, n);for (int i 1; i n; i){for (int j 1; j i; j){ret * j;}sum ret;}printf(%d\n, sum);return 0; }简单一些计算1! 2! 3!的阶乘之和。 首先看到我们进入了内存循环此时i 1, j 1内部的循环只会执行一次求出1! 1 此时的sum便为1 接着进入【2!】的计算内部循环会执行2次此刻i 2, j 1 此时算出ret 2即【2! 2】累加到sum中此时sum 3 接下去计算【3!】内部循环会执行3次3应该要为6此刻i 3, j 1注意观察此时的ret为2 当j 2时ret进行了一次累乘值便为4 当j 3时继续进行累乘此时ret为12 此时跳出循环开始累加【3!】的结果此时sum 15结果错误❌ 相信在认真看了我步步分析之后你一定可以清楚为什么会出错❓ 原因就在于每次在计算下一个数的阶乘时上一次累乘之后的ret没有进行一个重置便导致在计算下一个阶乘的时候重复累乘 这样运算结果就正确了1! 2! 3! 9 你觉得这篇文章真的就那么简单吗那我就不会写了上面只是热热身下面这个才叫做【真正的问题】 问题代码段2 —— 越界的危害 ① 发现问题 好我们来看这个代码段首先请你给出它最终的运行结果 相信很多同学都认为这段代码最后的结果是程序报错因为一眼就看出了for循环的边界条件有问题导致产生了数组访问越界如果你是这么想的那我要这么告诉你你是个正常人我问了我身边的朋友第一时间就觉得这一定是一个越界错误不过它的运行结果并不是你想的那样而是一个死循环 int main() {int i 0;int arr[10] { 1,2,3,4,5,6,7,8,9,10 };for (i 0; i 12; i){arr[i] 0;printf(hehe\n);}return 0; }② 分析问题 看了上面的这些结果相信很多读者都非常诧异(・∀・(・∀・(・∀・*)。究竟是为什么呢我们一起先来分析一下 通过调试来进行观察首先我们进入循环初始化数组 然后通过动图先将数组的合法10个元素修改为0这里的快捷操作是F9设置断点 F5运行到下一断点处 但是可以看到循环的终止条件为i 12那此刻循环就会继续执行那你就会想arr[10]这个位置不是越界非法的嘛为什么访问不会报错呢 首先我们来讨论一下arr[10]这个位置为什么可以访问到从下图可以看出在内存中对于一个数组而言是连续存储的数组后面的这些空间其实也是存在arr数组之后它们都存在于main函数的函数栈帧中对于函数栈帧来说一块块存储空间都是紧密相连的所以要想访问数组之后的空间也是可以访问到只是在我们的意识中他确实是存在越界访问的行为可能还是有同学不理解举个简单的【例子】假设你现在在一家酒店里和家里人一起出来旅游找了酒店中三个连在一起的房间住一晚上。你们旁边呢还有很多房间都是连在一起的那这个时候你可以闯入别人的房间吗虽然行为上是非法的但是呢又是可以做得到的只是会被人打一顿而已。这就可以理解为【数组的越界访问】 但是越界访问也就算了难不成真的可以修改没分配内部空间的值吗我们来看看 可以看到这个位置上的值确实是发生了一个修改Σ(っ °Д °;)っ而且没有报出错误继续循环。其实对于编译器来说有时候的越界访问不报出错误是正常的因为它有时候确实检查不到就和交警不可能查到每一个醉酒的司机是一个道理不然为什么有这么多车祸呢非但是可以修改第10个位置的元素后面第11个它也进行了修改。虽然这已经见怪不怪了 可是呢到了第12个位置的时候却出现了奇怪的事情这块地址上的数竟然不是一个随机值我们都知道面对未初始化的数据都是一个无符号整型unsigned int上面也看到过是一个很大的负数可是呢这个位置上的数确是12而且刚好是i 12这个边界的位置 此时当我再执行arr[i] 0时间就发生了这样的事此时的【i】和【arr[12]】两个值竟然同时发生了变化 那有同学就更加差异了这是为啥呀 ③ 思考问题【⭐堆栈原理⭐】 分析了问题出现的地方接下去就让我们通过堆栈的内存布局和原理来分析一下为何会出现这样的情况 刚才看到了当程序运行完arr[12] 0时arr[12]和【i】这两个位置的值一起发生了变化那就会思考它们会不会是一样的呢接着分别在调试的时候取出它们的地址就可以发现确实是同一块空间【我第一次看到这个结果的时候也感觉很惊奇】 其实就可以想到对于变量i应该是位于数组结束位置的后两位位置这样才会在越界访问数组的时候导致访问到【i】然后在修改这块块空间中的值时将循环变量【i】的值做了修改那也就使得【i】永远到不了13那也就不会跳出这个循环会一直循环下去 变量【i】辛辛苦苦地通过循环加到了13眼看前面的路就要走完了但是呢你又给他拽回了起点那也就只好重新开始。可是呢一次也就算了你就是和它过不去就站在13这个位置上每次看【i】一到13就把他拖回起点这也就使得它永远都过不去了 —— 血海深仇❣ 当然就通过这样的方式来看还是了解不到在内存中它们究竟发生了什么就下去我就通过画内存图的方式带你一探究竟 内存布局呢分为【堆区】【栈区】【静态区】三大块对于像arr数组和变量i这些都属于局部变量对于局部变量来说都是存放在【栈区】中的。也就是我们说过的函数栈帧它就是在栈区开辟空间的 栈也可以称做为【堆栈】它的使用习惯是先使用高地址再使用低地址。这一点很重要是理解的关键所在通过创建两个变量来进行观察就可以发现先创建的变量就会先创建的变量就会现在栈中为其开辟空间因此可以看到变量a的地址是比变量b的地址来得大的 下面我画的这张图其实就是内存中栈区的真正模样也就是从上往下进行生长上面是高地址下面是低地址。因此一进到main函数的函数栈帧中时就会先为变量【i】开辟一块空间接着可能就会空出几个位置再为arr数组开辟十个元素的空间 可是呢有同学就会疑问为什么要空出几个位置而不是直接紧随其后就在变量【i】后面为其分配10块空间呢这一点我们到后面再议 我们都知道对于数组的下标来说是从低到高进行变化的也就是从0 ~ 9那对于数组的地址是如何变化的呢我们通过VS来看看 通过打印数组中每个元素的下标就可以发现数组中每个元素的地址是由低到高进行一个变化的。这一点也很重要是理解的关键所在 然后再去看上面这张图你就可以知道为什么在越界访问数组的时候会访问到先创建出来的变量【i】了 虽然变量【i】是先创建出来的先开辟的空间而数组arr是后创建出来的后开辟的空间。不过呢因为数组的下标和每一个元素的地址都是从低到高进行一个变化的。又因为堆栈的使用习惯是先使用高地址再使用低地址所以当数组在进行向后访问的时候就有可能找到变量【i】就有可能把【i】覆盖掉就有可能把这个循环变量改成意想不到的值导致循环的结束条件永远都不会成立永远都是真这也就导致了死循环产生 你明白了吗 最后的话再来解释一下为什么开辟了变量【i】的栈帧空间后要空出几个位置才为数组arr开辟空间而且刚好是两个这么巧呢 其实这不是我瞎说的也不是我能决定的而是取决于编译器。 在VC6.0这个很老的编译器中其实在局部变量的栈帧空间开辟中是不会再创建多余空间的在gcc这个Linux环境下的编译器中创建的局部变量之间会空出一个整型也就是4个字节但是在VS 2013/2019/2022这些编辑器中中间都会空出两个整型也就是8个字节 所以这段代码其实你在不同编译器下去运行虽然都是死循环但是死循环的临界点和循环的这个范围都是不同的。例如在Linux下的gcc去编译运行的话i 11就会发生死循环具体的有兴趣可以去试试 ④ 解决问题【DeBug与Release】 好上面我们通过一系列的问题排查和思索最终发现了问题所在那现在就来更正一下这个问题 其实如何更正你已经可以想到了那就是把对于变量【i】的定义放到数组定义的后面这样数组在进行越界访问的时候就不会访问到后面的【i】了不过可以看到终于是出现了大家一开始想到的越界访问的情况 不过这种做法可是不对的数组越界访问应该是我们要避免的一个问题所以真正要做出修改的应该是循环中访问数组的结束条件 接下去我们再来看一个神奇的事情对于代码在编译器中的运行环境我们可以知道有【DeBug】和【Release】两个版本我将会出现死循环的这中定义方式放在两个不同的斑纹下进行了运行查看变量i和数组的边界地址 然后便发现【Relsase】版本对变量i的地址做了一个优化使其变到了数组arr的前面这样在数组向后进行越界访问的时候就不会发生覆盖造成同时修改了 希望在看了我上述对这个问题的讲解之后今后在碰到类似的问题也可以照常去分析排查 程序员与测试人员 说一个程序员和测试人员之间的小故事 在公司里面有产品经理有部门主干有安全人员有运维人员也有程序员和测试人员但是我们都流传着对于程序员和测试人员是【仇敌】为什么这么说呢因为程序员只需要实现当前这段给他的业务逻辑不需要考虑其他内容所以他就专注于这块的实现因此对自己的代码很有信心。可是呢人无完人每个人都会出错不然程序员为何要修这么多BUG呢当测试人员在他的电脑上运行开发部发来的代码时却出现了问题可能是栈溢出、访问异常或者是我们上面说到的访问越界当她排查了半天发现代码逻辑有问题时就非常气愤地找到写这块逻辑的程序员 此时就开始了它们的一些争吵。。。。。。。。。此处省略一万字 两个人就这么吵了几十分钟然后旁边一个资深程序员看不下去了过来帮忙看了看运行测试了一下发现这块代码逻辑在【DeBug】和【Release】环境下得到的结果是不一样的。这也就解开了两人之间的矛盾一对照便知原来测试人员使用的是【Release】环境而程序员使用的是【DeBug】环境 对于DeBug环境下运行代码会保留很多的调试信息供程序员测试代码逻辑对于Release环境下运行代码会省略很多的调试信息可能刚好省略了什么重要的内容 所以在工作的时候若是发现和测试人员对口的内容不一致可以去看看运行环境是否一样 ✒总结与提炼 来总结一下本文所学习的内容 首先我们通过一个简单的问题代码段教了大家如何去使用调用排查问题算是进行了入门接着通过一段看上去简单但是内部逻辑很是复杂的问题代码段较大家如何去一步步地排查、分析、思考问题通过画出堆栈的原理图找出问题所在继而解决问题最后我们通过【程序员与测试人员】之间的故事知道了原来在DeBug和Release环境下运行的代码可能会出现不一样的结果也多了一个和测试人员解决问题的手段 以上便是本文要介绍的所有内容感谢您的观看记得给个三连支持哦❤️❤️❤️
http://www.sczhlp.com/news/208309/

相关文章:

  • PWN手的成长之路-18_铁人三项(第五赛区)_2018_rop
  • Dotnet通过Http2解决CVE-2025-55315高危漏洞
  • 元推理框架,有机AI是天使
  • 重庆建设工程质量协会网站网站建设图片logo
  • 网站建设设计有哪些英茗网站建设
  • 自建站有哪些建设银行人才招聘网站
  • 长春站建了多少年手机推广app
  • wordpress评论滑动插件google seo是什么意思
  • 浙江住房与城乡建设部网站自己建公司网站可以嘛
  • 中国水土保持与生态环境建设网站海口顶尖网站建设
  • 网站建设运营公司排行专业建网站价格
  • 做网站赚钱好难app图标制作软件
  • 怎么建立网站网址个人主页自助建站
  • 佛山网站建设联系微信app下载安装官方版2022网址
  • 广西工程建设质量管理协会网站建筑工程 技术支持 东莞网站建设
  • 高端网站定制设计公司网站建设合同需要交印花税
  • 永春网站建设查商家信息有哪些网站
  • 精仿手表网站软件制作权
  • 企业官方网站认证高端营销型网站建设
  • 营销型网站设计稿如何更快的学习.net网站开发
  • asp网站后台模板太原网站制作推广
  • 做招商类型的网站重点建设专业 专题网站
  • 客户网站 备案网站怎样注册
  • 做cpa推广用哪种网站好gdrp wordpress插件
  • 网站服务器类型山西省煤矿建设协会网站
  • 免费php企业网站源码宁波网站建设设计至诚服务
  • 龙泉网站建设网站开发公众号开发
  • 东营网站建设推广百度云wordpress教程视频教程
  • FFT学习小结
  • OI 笑传 #20