前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >定位并解决程序错误

定位并解决程序错误

作者头像
bugsuse
发布2020-04-21 17:28:00
1.1K0
发布2020-04-21 17:28:00
举报
文章被收录于专栏:气象杂货铺气象杂货铺

不管你用的什么编程语言,从你接触她开始就注定了你们相爱相杀的一生。为了增加生活乐趣,她会时不时给你来点小惊喜。

无论是在论坛还是交流群,时不时的都会有人问:程序不能运行了,怎么办?程序出错了怎么办?有时候运气好了还会有人冒个泡多问一句,但大多数时候,碰到上面的问题,是得不到回复的。主要原因在于提问方式,关于提问的智慧,这里不说这些。

其实在编程过程中出现的很多问题别人大多也遇到过,而且网上有解决答案。只需要两步:

以上能帮你解决大多数小错误,但是当遇到稍微麻烦一些的问题时,该怎么办呢?

下面以MATLAB为例,说一下当程序出现错误时,如何根据提示定位到实际发生错误的地方,然后更改并顺利运行程序。

Skew-T是气象领域比较常见的一种图,气象家园中有些帖子中提供了matlab脚本[注1],可以绘制此类图。大多数情况下,帖子中提到的脚本都能顺利绘制出图,但是有些情况下会出现一些问题。比如当绘图所需要的探空数据较少时。探空数据由怀俄明大学探空数据网下载[注2]。

如下图,完整的各参数值只有6行,每个参数只有6个值,这就会导致程序运行出错。

运行程序之后会出现图中所示的错误提示。按照上图标注的顺序:

  • 首先定位错误提示信息第一行。
在赋值 A(:) = B 中,A 和 B 中的元素数目必须相同。

错误提示表明,A数组和B数组大小不同。需要检查这两个数组。那哪两个数组对应A和B数组呢?

  • 然后定位程序调用错误行并回到 skewTlogP_plot 程序中提示出错的行 Handle_line(4)=plot(x_loc.*ones(size(pzff)), pzff); 确定此行之后,按照上面的错误提示信息,找到A和B数组;
  • 上述语句中的 Handle_line 为 A 数组,而 plot(x_loc.*ones(size(pzff)), pzff) 的结果为 B;
  • 然后查看变量 x_loc 和 pzff,可以确定pzff为空,从而定位到变量 pzff 出错;
  • 继续定位 pzff 值的来源,找到下图中 pzff 的源头,可以发现 pzff 的值在if else 判断语句中确定,在79和84行添加断点确定在哪部分执行
  • 确定在 else 部分执行之后,继续查找 pz 变量和 Series 变量,从变量空间(matlab工作区)可以发现,Series为空,即pz索引值为空,从而导致出错,而Series赋值语句为 1:round(N/20):N,其中只有变量N,查找变量N的值为6,round(6/20) 等于 0,生成序列时,步长为0,导致序列为空

生成序列时,步长必须为大于等于0的数,而round执行的是四舍五入操作,当数小于0.5时结果为0,从而导致程序出错。只要N小于10,上述程序就会出错,这是skewTlogP_plot 程序的bug。

解决方法:将下图红框中所示代码添加到源程序中即可。

除了平时上面的例子之外,不得不吐槽的是国内的闪电数据格式,是目前遇到的处理起来最让人头疼的数据,没有之一,不是因为数据结构复杂,而是数据本身出错率高。

下面以处理闪电数据为例,讲一下如何定位程序错误[注3]:

由于闪电数据的数据量大,通常需要进行批量处理,而由于闪电数据的错误率高,说不定某一个文件就会有一行记录出错,或是某一行出现乱码。如果不在处理过程中额外输出信息的话,想要确定真正的错误内容会比较麻烦。

如下图,处理过程中出现的问题:

  • 首先,定位到错误提示第一行 索引超出矩阵维度。这是使用matlab最常见的错误之一。如果你已开始不知道这是什么意思,可以搜索一下。这种错误虽然常见,可能你也知道是什么意思,但是究竟是什么原因导致了这种错误呢?继续往下
  • 然后,定位到出错信息的程序调用提示部分,这部分会定位到是哪个程序的哪一行出错了,程序调用顺序为 debug 调用 getflash ,getflash调用 getadtd子程序,getadtd子程序调用 processData子程序。调用顺序由下向上。即最终导致出错的是 processData 子程序的部分,即218行 出错 getflash>processData (line 218) if (proll && strcmp(file_data{1,10}{j,1},p.Results.provinces)) || (~proll) 出错 getflash>getadtd (line 91) data = processData(files, filepath, file_num,proll, 'provinces', p.Results.provinces); 出错 getflash (line 58) flash = getadtd(p.Results.file, 'provinces', p.Results.provinces); 出错 debug (line 7) data = getflash(filepath, 'adtd', 'provinces', '江苏省');
  • 定位出错变量,这时候就需要之前的索引超出矩阵维度的错误提示了。查看第218行的变量有哪些,并确定其值。只有 file_data出现了索引,而且只有 j 是索引中的变量,查看 j 的值,并确定 file_data 的维度,查看file_data的值,可以发现file_data{1,10}为1行1列,而j为2,从而导致索引出错
  • 找到上面算成功了一半,由于j出于for循环中,而这部分又是用于处理文件,而命令窗口的输出信息显示处理了8个文件,说明处理第9个时出错,查看第9个文件,发现第3行出现数据缺失
  • 删除第3行数据,然后可以继续处理

通过以上两个示例可以发现,定位错误的时候是有流程的:

  • 首先,定位错误信息,通常是错误提示的第一行(不包括程序调用提示)
  • 如果确定错误信息后能够解决,则跳过以下步骤;否则继续以下步骤
  • 定位程序调用提示,并确定每部分出错的信息
  • 如果所有程序都不是matlab自带的程序,则由下向上定位到最上面的程序,然后定位到错误行,同时结合第一步给出的错误提示信息,然后确定可能导致出错的变量;如果有些程序是matlab自带的程序,则定位到自定义程序即可,一般情况下matlab自带的程序出错的可能性很小,所以有限检查自定义程序,然后继续检查
  • 逐步定位和导致出错的变量相关的变量信息,直到最终确定导致出错的边来给你,同时了解出错部分的作用。如果在判断语句,通过加断点确定哪部分执行;如果在for循环中出错,可借助for循环的循环顺序变量,确定执行到了哪一步,比如i,j
  • 通常到这里就能够确定最终的错误所在,然后修改之后就能运行了

无论是对于新手还是老手来说,MATLAB在debug程序方面都是非常友好的,其强大的图形界面也是MATLAB的优势之一。编程语言都是互通的,无论你使用的是python,matlab,ncl,julia还是R,或go,对了最古老的语言之一——fortran,当程序出错的时候都会抛出一个错误提示,只要你理解了错误提示,然后掌握一定的debug技巧,基本上能解决大部分问题。

当然,有些错误是很难发现的。比如:程序能运行,也没有错误提示,但是最后的结果缺不是你想要的。遇到这种情况,只能去看程序源码,然后根据变量信息来排除。这时候,除经验和技巧之外,需要的就是细心。


注1:http://bbs.06climate.com/forum.php?mod=viewthread&tid=27252&extra=

注2:http://weather.uwyo.edu/upperair/sounding.html

注3:http://bbs.06climate.com/forum.php?mod=viewthread&tid=42183&extra=

注4:链接: https://pan.baidu.com/s/1geYfwyv 密码: 2m5y

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 气象杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档