debug调试技巧

来源:互联网 发布:网络舆论引导 编辑:程序博客网 时间:2024/06/10 17:24

还在断点调试?教你四种调试技巧让你快速定位错误!

 2017-01-07 令狐冲 九章算法

在九章做老师的这段时间,许多同学经常把一个程序直接贴给我说:


老师,我的程序出错了,帮我看看吧。

对于这些同学的请求,我往往只能委婉的拒绝:


调试要靠自己哦~ 我帮你指出程序的错误,对于你自己一点帮助都没有。你今天先继续努力debug,明天要是还不能解决,我就帮你看看。


虽然大部分同学最终也都能靠自己的努力找到错误,但是学会好的调试技巧,确实能够起到事半功倍的刷题效果。于是我总结了四种我自己常用的在刷题过程中的调试技巧,希望可以帮助到大家:

1技巧1: 打印中间结果


依赖于IDE的断点调试,是十分浪费时间的一种调试方法。而且在面试中,你是基本没有断点调试的机会的(因为很多公司是白板写题,不会提供给你IDE)。事实上在实际的工作中,你也很少能够有机会去进行断点调试,比如你进行的是 Web 开发,你只能想方设法的在代码中打印一些 Log,然后根据 Log 去分析出错的原因。你平时用 IDE 写代码,就十分容易养成这种断点调试的“坏习惯”。一个更好的方式,是使用打印中间结果的方式。以 LintCode 上的 Clone Graph 为例子:



LintCode 支持自己出测试数据进行测试的模式,点到“Testcase” 这个 tab之后,输入测试数据,点 Run Code。你的程序中的输出也会被显示在 Output 中。我们看到 代码中 第22行到27行,是在打印一个中间结果,这个中间结果就是在使用了  bfs 算法之后,从一个点出发,找到的所有的图中其他节点。这样我们就可以迅速验证,代码出错到底是因为 BFS 写错了,还是因为其他的部分写错了。


使用这种调试方法的另外一个好处是,你很自然的希望你的程序可以“分阶段”输出一些中间结果,这种分阶段处理的方式,也是我们在课上经常强调的,把大问题变成小问题,然后逐个击破的编程思想。养成这种编程习惯之后,可以非常有效的帮助你在写程序的时候,就避免掉错误。


2技巧2: 一行一行改成参考程序 


在九章的官网 http://www.jiuzhang.com/solutions/ 中有 LC 完整的参考程序库,其中 Java 程序的一部分代码是我自己亲自编写的,具备较高的质量和参考价值。很多题目也给了多种不同的解法。比如 Binary Tree Level Order Traversal 这一题,给出了三种 BFS 的参考程序和 1个 DFS的参考程序:http://www.jiuzhang.com/solutions/binary-tree-level-order-traversal/。通常来说很多题目,你不仅仅需要掌握其中一种方法,而是需要掌握这个题所有的解决办法。


有不少同学经常会来问我:“老师,我的代码和参考程序一样啊,为什么还是不对。” 这种时候,我通常建议他们,将自己的代码,一行一行的改成参考程序。这样,当他们发现哪一行代码不一样的时候,就自然定位到了错误。


举一个例子,就以 Binary Tree Level Order Traversal 为例,宽度优先搜索算法(BFS)是面试必须掌握的一种算法。来看看下面这个有错误的代码(请花3分钟阅读一下,并找出错误所在):



从程序思想上来看,好像并没有什么错。很难直接发现有什么问题。与参考程序逐行对比之后会发现,错误发生在第14行。


参考程序中,写法是:



和上面的程序写法是:



这两种写法存在巨大区别,原因是在循环体内部,我们会不断往 queue 中放东西,这导致了queue.size() 的值是不断变化的。而没有起到我们只想循环当前这一层所有点的功能。


通过对这个程序逐行对比,我们能够马上学会如下的知识点:


  1. for循环中间的判断语句,在循环体的每一次循环中都会被重复执行,而不是在一开始就确定好执行多少次。

  2. 为了做到BFS的分层遍历,需要先把 size 取出来,再 for循环这个size,这是BFS分层遍历中最关键的一句话。


3技巧3: 给小熊讲程序 


这个技巧,是我曾经参加高中生算法竞赛的时候,一位算法竞赛国家队的前辈教我的。当时我的算法水平可能已经还不错了,但是代码质量很差,很容易写出有bug的代码。这位前辈告诉我,可以放一只 “小熊” 在你的电脑旁边,一旦程序出错了。就对着这只小熊讲你的整个代码是怎么解决问题的。因为是给小熊讲,所以你可以把它当作什么都不懂,于是需要更加仔细的去讲述你代码中每个细节,所以你需要一行一行的讲,甚至连为什么你要用 ArrayList 而不用 int[] 都要讲得清清楚楚。讲着讲着,你就有可能突然发现你的错误所在了。


这个技巧的意义在于,你在写代码的时候,脑子里可能想着一个事情,但是打出来的代码,可能是另外一回事儿。或者你脑子里想着有3个条件需要判断,但是打的时候,漏掉了一个。当你把代码重新讲一遍的时候,事实上是在重新整理你的逻辑,查漏补缺。这样很容易就能够发现你的错误。


4技巧4:  必杀,重写一遍 


大部分的bug,其实都是 typo。比如:


  • 大于符号和小于符号打反了

  • <= 写成了 <

  • 本来要写一句话干什么来着但是后来写着写着忘记了

  • if 后面忘了加 else

  • for 循环后面忘了加括号,导致代码跑到了循环体之外

  • 变量名打错:for(int j=0;i<n;j++)


诸如此类,不胜繁举。重新写一遍代码, 往往都能 fix 这些问题。


5尾声


调试是在你出现 BUG 的时候,才需要做的事情。大家平时应该尽量去练习的是不要写出有BUG的代码。这很难我知道,但是你应该以此为训练目标,在你在 LintCode 上点击 “Submit” 之前,尽量的做到已经检查过自己的代码,不要过分依赖于 Online Judge帮你判断你的代码是否有错,更加不要依赖于本地 IDE 的断点调试功能。LintCode上有一个指标,在http://www.lintcode.com/problem/ 这个界面(登陆后可见):



这个指标非常的重要,他是判断你的代码是否 Bug Free 的重要参考数据。如果你最近一个月内的这个数据在 3 以内,那么说明你的代码具备非常高的质量,不太容易出bug。如果在3-4之间,说明,还可以有所提高。如果在4以上,说明,你的代码质量比较糟糕了。


最后,下下周,我们会在LintCode上举办一次九章算法班第23期的期中考试(考试时长约2-3小时,具体考试时间待定会邮件通知),也欢迎之前的老学员来参加。期中考试仅限学员参加,题目是由我根据最近的面试趋势和已经讲授的内容出的新题,不容错过。


想进FLAG?九章帮你系统讲解面试算法,解决面试时常见算法问题


以下课程,正在报名中!

《九章算法班》

《算法强化班》

《Java入门与基础算法班》

《Big Data 项目实战班》

第一节免费试听!!

报名网址http://t.cn/RAC7Era, 或猛戳“阅读原文”



原创粉丝点击