编码入门加器-介绍两个Debug的方法

编码入门加速器-分享两个Debug的技巧

作者:老九—技术大黍

社交:csdn

公众号:老九学堂(新手有福利)

特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系笔者授权

前言:

对于C/C++初学者而言, 出现bug是一件非常头疼的事情, 但如果掌握了技巧, 找bug就是一件很容易的事情了.

其实,我们程序员就是一群调bug的人而已。没有开发过的人肯定不会同意我这句话,但是,我相信这句话对职业老鸟们来说,一定不会反对。

今天我们用C语言和Visual Studio 2019来介绍两个Debug的方法 调试的基本用法二分法查找bug, 以及比较经典的小黄鸭查找法.


调试:

逐步执行定位问题 是找bug最好的方式, 那么这里就出现了两个重点 逐步(逐行执行)与定位(每个值的变化).

相信很多初学者 在代码遇到bug时, 都会习惯用[打印语句]来手动实现调试.

比如可能绕晕过小伙伴的冒泡排序:


小白 : 大佬帮我看看哪里有问题

image-20210318211735335.png

for (int j = 0; j < len - i - 1; j++) {
    if (arr[j] > arr[j + 1]) {
        temp = arr[j];
        arr[j + 1] = arr[j];
        arr[j + 1] = temp;
    }
}

image-20210318210647956.png

张三:加上打印语句试一试就知道了!

image-20210318211810573.png

..3分钟后

for (int j = 0; j < len - i - 1; j++) {
    if (arr[j] > arr[j + 1]) {
        printf("0: %d,%d,%d\n", arr[j], arr[j + 1], temp);
        temp = arr[j];
        printf("1: %d,%d,%d\n", arr[j], arr[j + 1], temp);
        arr[j + 1] = arr[j];
        printf("2: %d,%d,%d\n", arr[j], arr[j + 1], temp);
        arr[j + 1] = temp;
        printf("3: %d,%d,%d\n", arr[j], arr[j + 1], temp);
    }
}

image-20210318211316622.png

"emmmmmm, 似乎是1和2周围出现的问题." image-20210318211932484.png

"找到了! 需要将arr[j + 1] = arr[j]; 修改成arr[j] = arr[j + 1];"

image-20210318212014109.png 这种方式, 虽然看起来很好用. 但手动加上打印语句实在太麻烦了, 而且加上打印后 代码可读性变得很差.

另外, 由于不能中间暂停(加上scanf后可读性更差了), 输出测试会被前后的打印语句所影响, 输出也不好看.

我们代码圈有一句经典名言: "不会偷懒的程序员不是好程序员".

于是, 就要请出我们的主角: 集逐步与定位于一身的调试功能.

在开发中, 我们会经常采用调试来跟踪代码运行. 代码运行过程中出现bug时, 启用调试可以快速找到bug出现的位置, 以及在运行时变量值的变化.

举例:

在这里我们用VS2019举例(由于篇幅限制, 本章就跳过其他编译器的调试说明了, 小伙伴如果有需要可以自行百度)

首先, 在需要调试的代码行左边点击一下(打上断点), 表示程序运行到此处时暂停

image-20210318203858973.png

接着, 启动调试器.image-20210318203956332.png

现在我们就进入了VS2019的调试界面

image-20210318205322956.png

在这里, 我们可以手动控制程序的运行速度, 并且每一步 都可以在监视区看到每个变量的状态.

于是, 我们就可以很快的看到.

1:

image-20210318210104569.png image-20210318210116282.png

点击下一步image-20210318210902063.png

2: 这里temp值变红 表示temp的值有了变化

image-20210318210153160.png

点击下一步image-20210318210902063.png

3: 很明显 这里arr[j+1]的值也被改变了. image-20210318211649552.png

image-20210318210244453.png

按照正常的交换流程, 接下来就是给arr[j]赋值为tem......

image-20210318211603514.png等下! temp的值 好像上一步就被改变成10了

bug找到了! 在第2步时, arr[j+1]的值是9, arr[j]的值是10,temp的值也是10.

按顺序应该是将arr[j+1]的值赋值给arr[i]才对!


小结:

使用调试功能, 只需要在可能出现bug的代码前打上断点, 即可开始逐步调试. 相比使用打印语句来找bug, 不仅省事了很多, 而且界面也看起来高大上!

学会调试前:

image-20210318211341046.png

学会调试后:

image-20210318210244453.png

我们学会了吗?

image-20210318211458448.png

二分法:

二分法, 我们通常也叫折半法.

是一种将区间逐渐变小, 直到查找到指定位置的方法.

首先, 我们在预估有bug的代码块中间打上断点(注意 这里中间是指运行过程的中间, 而不是代码行的中间)

如果值在前面就出现了异常, 说明是前半段逻辑的问题

如果值没有出现异常, 说明是后半段逻辑出现了问题

接着在前半段/后半段代码块的中间打上断点 重复以上步骤即可

举例:

这里我们随机抽取一个小伙伴的作业 image-20210318211458448.png

题目:

image-20210318220548802.png

某个小伙伴的代码:

image-20210318215626892.png

然后悄悄的改一点, 使其出现bug

image-20210318215737027.png

死循环了image-20210318215838854.pngamazing!

接下来 我们就要开始调试查找了


在循环的末尾打上断点, 并运行

image-20210318221239349.png

第一遍

​ half的值是candy每个元素/2 candy的每个元素值都是[i] = half[i] + half[i+1].

(这里是举例教大家如何调试, 所以这段代码不需要深究. 日常调试中能看出来值是否有问题就可以)

运行正确

image-20210318221952731.png 点击这个按钮, 表示跳到下一个断点. 由于我们只有一个断点 所以会跳到下次循环的这一行

image-20210319093006564.png

第二遍:

candy的值出现问题了所以可以判断 是第二次循环开始 值出现了异常


现在我们将断点打在程序的中间, 然后启动调试, 直接进入第二次循环

image-20210319100156897.png

上半部分的代码是将数组平分, 所以按理candy和half的值应该是相同的才对.

上半部分的代码出现了问题


接着我们在上半部分的代码中打上断点 逐步调试 .

由于上半部分的代码是单个循环, 里面放了判断分支, 所以直接在循环处打上断点

image-20210319101151455.png

同样跳到第二次循环, 开始调试,

image-20210319101359663.png

第一遍进入了if部分, 值正确.

看来是else部分出现的问题


由于下次循环就进入else了, 这里可以不用再打断点重新调试.

马上就要接近bug的真相了!

进入else后, 元素的值并没有相等

问题就在else的两次赋值中出现了

image-20210319101616356.png

现在我们看看else的代码

image-20210319101743707.png

candy[i]先自己/=2 然后给half[i]赋值时再/2. 于是导致了half[i]接收到的值 实际上是candy/4的值.

解决方案就很简单了, 只要先candy给half赋值 再自除就好了

image-20210319102016587.png

搞定!

修改代码后, 运行一下试试

image-20210319102055853.png

解决了!image-20210319102222500.png

总结:

现在我们总结一下找到bug的流程

image-20210319105708810.png

最开始 我们通过在循环逻辑处打断点的方式, 先找到了程序运行第X次循环时出现的问题

image-20210319110214089.png

接着, 我们在第X次循环的中间打上断点 发现是上半部分出现的问题

image-20210319110301480.png

然后, 在上半部分的代码中调试, 发现是else部分的bug

image-20210319110450396.png

最后, 查看else部分的两行代码, 发现了问题

image-20210319102016587.png

大家学会了吗?

image-20210318211458448.png

小黄鸭调试法(补充)

某天, 张三在食堂看到同学李四愁眉苦脸, 于是问"你怎么了?",

"唉, 我遇到了一个bug. 我的代码需要实现balabala, 于是 我想着先alala, 然后再balabala, 后来在clacl... !" 李四灵光一现, 于是中断了聊天, 饭也没吃完就回去改bug了.

相信很多小伙伴都有这样的经历, 遇到bug卡住了, 在和他人描述的中途找到了解决办法.

其实这种方式有一个术语: 小黄鸭调试法.

小黄鸭调试法是软件工程中使用的调试代码方法之一。就是在程序的调试、纠错或测试过程中,耐心地向小黄鸭解释每一行程序的作用,以此来激发灵感。

举例:

需要准备的内容:

1.一只小黄鸭(或者长得像小黄鸭的任意物品):

9A40032DFBBA79AF8ED63624EC6A027E.jpg 出来吧皮卡丘, 就决定是你了!

2.一段有代码的bug

image-20210319114720467.png

如果你不希望让别人看到:

找bug找了很久的同学 似乎入魔到想教会手中的玩偶写代码.jpg

这样的奇景. 你还需要一个安静的空间.

接下来就可以开始对着小黄鸭进行介绍每段代码的功能了:

2CB09C33C4BA49476F3EC03DC47BCC22.jpg

接着愉快的找到了bug

image-20210319140524953.png

以上就是一些找bug的常见技巧, image-20210318211458448.png 大家学会了吗?

代码bug出现的方式千奇百怪. 相应的, 找bug的技巧也多种多样. 大家平时在学习中有哪些好用的小技巧, 也可以放在评论区大家一起交流, 讨论.

最后

感觉有用的同学,请记得给大黍❤️关注+点赞+收藏+评论+转发❤️

作者:老九学堂—技术大黍

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值