配色: 字号:
《Visual Basic 2005 程序设计》第4章 程序调试和错误处理
2023-05-25 | 阅:  转:  |  分享 
  
第4章 程序调试和错误处理本章主要内容:程序设计中的错误类型。设置断点,程序执行过程控制,监视变量值的变化。异常处理概念及使用。前面讨论了程
序设计中的数据及其表示和存储、以及对数据进行处理的算法的基本结构。大家可能已经注意到,在编写程序时,经常可能出现各种各样的错误。对
于一些语法错误,Visual Studio 2005的智能感知IntelliSense能够及时给出提示,但对于一些逻辑错误、运行错
误,如果没有相关代码进行处理,则可能出现一些系统提示的错误信息、或造成死机等意想不到的情况发生。为此,程序代码需要程序设计人员进行
大量的测试和调试,减少代码语句、逻辑出错的可能性。因此,培养程序调试的技巧与能力,以及对程序中可能出现、或潜在的错误能够及时进行处
理,是程序设计人员必须掌握的技能。4.1 错误类型常见的错误类型有3种:语法错误,执行错误和逻辑错误。4.1.1 语法错误Visu
al Studio 2005智能感知IntelliSense能够对一些语法错误进行及时的提示,有些语法错误通过自动错误纠正功能进行
纠正,但有些错误需要程序设计人员进行分析,根据实际情况进行解决。⑴ 有些简单语法错误是由于当前语句引起的,这种语法错误的发现和解决
都比较简单。例如:在例3.13中计算最小水仙花数的代码中,如果把Loop Until误输入成Loop Untile时,Visual
Studio 2005智能感知IntelliSense会在Untile下显示波浪线,当光标移到Untile上时,提示信息显示“语
法错误”,如图4-1所示。同时,在错误列表窗口中显示该错误的简单说明,错误的准确定位(该错误出现的项目名及其文件名,在文件中的行列
号),如图4-2所示。提示:用鼠标左键双击错误列表中的错误信息行,光标会自动移到该错误对应的程序代码上,并自动选择出错的代码。⑵
有时Visual Studio 2005智能感知IntelliSense提示的错误位置,并不是真正引起错误的位置,错误可能发生在其
它位置的语句上。例如:在例3.13中计算最小水仙花数的代码中,如果把Loop Until误输入成Loopp Until时,Visu
al Studio 2005智能感知IntelliSense会把Loopp、Until自动看成方法,用括号把Loopp后面的内容括
起来,同时提示三处错误信息,如图4-3所示。同时,在错误列表窗口中显示所有错误的简单说明,如图4-4所示。如果只看第3个错误,则可
能莫名其妙,因为Until没有错误!第一个错误是由于没有与之匹配的“Loop”,如果采用自动错误纠正功能,纠正后的Loop也不会自
动放在Loopp处,更不会使用Loop自动纠正Loopp,如图4-5所示。对于这类错误,要从前面的错误开始,综合分析,不能只看单一
的错误提示信息。其实只要根据第一个错误的提示信息,找Loop的位置,进而会发现Loopp错误,即第二个错误,把Loopp改正了,则
所有的错误也就解决了!这类错误在程序设计中经常出现,因此,程序设计人员要多编程练习,多积累经验,才能快速的定位、解决这类语法错误。
4.1.2 执行错误执行错误是指在运行过程中由于某些情况的出现,而引起的错误,如果没有出现没有预知的情况,则程序可能不会出现错误。
例如:如果程序要通过网络访问数据库服务器读写信息,如果数据库正常运行,而且运行该程序的所有计算机能够顺利访问到数据库,则程序可能不
会出现错误。但如果数据库由于某些原因停止了工作,这时程序如果把信息写到数据库,则可能造成数据丢失!防止产生执行错误的最好办法是在错
误发生之前预计可能出现的错误,并通过错误处理技术捕捉和处理错误。4.1.3 逻辑错误逻辑错误是指产生预料之外或不希望的结果的错误,
产生这类错误的原因是多方面的,可能是算法设计有问题,或程序编写有错等。例如:计算1+2+ … +100的和,有如下代码:Dim i
ntCon As Integer = 0Dim intSum As Integer = 0Do While intCon <= 1
00 intCon +=1 intSum += intConLoop上面的代码没有任何语法错误,但运行结果不正确,其原
因是存在逻辑错误,可以这样分析:在开始Do While循环时,intCon的值是0,当执行完intCon += 1后,intCon
的值则为1,这时intSum += intCon的执行结果是把1加到累加和intSum中。然后进入下次循环,可以看出,这种累加没有
错误!现在分析退出循环时,如果循环到intCon的值是99,则Do While intCon <= 100为True,继续循环,执
行完intCon += 1后,intCon的值则为100,这时intSum += intCon的执行结果是把100加到累加和int
Sum中。然后进入下次循环,这时Do While intCon <= 100还为True,则后面执行的结果是把101也加到累加和i
ntSum中!然后进入下次循环的判断,Do While intCon <= 100为False,退出循环!即上述代码累加的是1+2
+ … +100+101,这与计算要求不符!解决上述错误的方法很多,可以把intCon <= 100改为intCon < 100,
或把intCon += 1语句放到intSum += intCon语句的后面。4.2 程序调试程序调试是程序设计中必不可少的一部分
,无论是经验丰富的程序开发人员,还是刚开始学习编写程序的新手,都会犯错误。因此,养成良好的程序调试习惯,培养程序调试技能,才能写出
好的程序。Visual Basic 2005 为程序设计人员提供的最基本的程序调试方法是设置断点,跟踪程序的运行过程及变量值的变化
,进而发现程序中的错误。例4.1 通过文本框输入一个整数,如果是负数,则转换为正数,并计算1到该数的累加和,通过输出文本框输出。
具体操作过程:⑴ 新建项目,选择“Windows应用程序”, 项目名称为“累加数”。⑵ 在解决资源管理器中把“Form1.vb”文
件名改为“累加数.vb”。⑶ 打开窗体设计视图,选择Form1窗体,在属性框中修改窗体的属性:Name为“frmConsecula
te”;StartPosition为“CenterScreen”;Text为“计算累加数”。⑷ 为窗体添加两个Label控件,Te
xt分别为“请输入一个整数:”、“累加结果:”。⑸ 为窗体添加2个TextBox控件,Name分别为“txtInput”、“txt
Output”。其中txtOutput控件的ReadOnly为“True”。提示:TextBox控件的ReadOnly属性为Tru
e时,该文本框内容只读,即该文本框不能通过键盘输入内容,但可以在程序中更改Text属性的值。⑹ 为窗体添加1个Button控件,修
改该控件的属性:Name为“btnConseculate”,Text为“累加”。⑺ 双击“累加”按钮,在代码编辑器中添加对“累加”
按钮Click事件响应的代码: Private Sub btnConseculate_Click(ByVal sender As
System.Object, _ ByVal e As System.EventArgs) Hand
les btnConseculate.Click ''定义变量 Dim intNum As Intege
r = 0 ''保存输入的数 Dim intCon As Integer = 0 ''累加控制变量 D
im intSum As Integer = 0 ''保存累加结果 ''读取输入的内容 If Not (IsNumer
ic(txtInput.Text)) Then MessageBox.Show("输入的内容包含非数字字符!
", "错误") Exit Sub End If intNum = CInt(txtIn
put.Text) ''把输入的字符串内容转换为Integer数值类型 ''如果输入的是负数,则转换为正数
If intNum < 0 Then intNum = -intNum End If
''累加过程 Do While intCon <= intNum intCon += 1
''累加控制变量递增 intSum += intCon ''累加 Loop
''输出累加结果 txtOutput.Text = intSumEnd Sub运行“累加数”程序,在文本框中输入100,则在
输出文本框中显示累加结果为5151,可以看出,上述累加的结果不正确,但程序没有提示任何错误信息。这说明程序中存在逻辑错误!4.2.
1 设置断点为了查找程序中的逻辑错误,需要跟踪程序运行过程及变量值的变化。跟踪方式是通过设置断点,让程序运行时暂停在指定的语句处,
然后查看变量的当前值。设置断点的方式很简单:方法1:在代码编辑器中将光标移到需要设置断点的语句上,按F9键则在该位置设置断点;如果
光标在设置了断点的语句上,按F9键则取消该位置的断点设置。方法2:鼠标左键单击需要设置断点的语句行对应的编辑器左侧的灰色条,可以设
置断点;用同样的方法可以取消已经设置的断点。设置断点后的语句上用特殊颜色显示,并在对应的行前显示一个红色的圆点,当光标移到该圆点上
时,显示断点设置的位置的信息。如图4-7所示。4.2.2 控制程序执行当程序执行到断点位置时,程序运行会暂停并切换到代码编辑器窗口
中的断点位置。如果要让程序继续执行,可以:按F5键,或单击菜单中“调试|继续”,或单击工具栏中的,程序继续执行。按F8键,或单击菜
单中“调试|逐语句”,或单击工具栏中的,程序逐语句执行。按Shift+F8键,或单击菜单中“调试|逐过程”,或单击工具栏中的,程序
逐过程执行,即碰到过程时直接运行过程,不会提示进入过程的执行过程。按Ctrl+Shift+F8键,或单击菜单中“调试|跳出”,或单
击工具栏中的,程序跳出当前断点继续执行。当程序中断或单步执行时,在当前执行的语句的左侧会出现一个指示箭头,如图4-8所示。把光标移
动到指示箭头上,可以按住鼠标左键移动指示箭头到其它语句上,则程序会在指示箭头的新位置开始继续执行。比如直接移动到txtOutput
.Text = intSum语句,则执行输出结果的语句。图4-9是当输入数为10时,正常运行结束结果如图(a)所示;当累加过程执行
几次后,移动指示箭头跳过累加过程的结果如图(b)所示。可以看出,移动指示箭头跳过某些代码可能引起执行结果不正确!4.2.3 跟踪变
量值在程序调试时,通过在程序中设置断点,或启动逐语句、逐过程执行时,都可以让程序运行时暂停在指定的语句处,然后查看程序的运行状态。
而程序的运行状态主要体现在程序中变量的当前值。因此,在调试程序时,主要是要跟踪变量值的变化,进而发现程序中的逻辑错误。在程序调试时
查看变量和表达式的当前值的方式主要有:⑴ 在编辑器中实时查看:当程序暂停在指定的语句处,当光标移动到程序中有效的变量上时,会弹出该
变量当前值的说明。例如:通过F8键启动逐步执行,在文本框中输入10,当程序运行暂停于图4-10所示的“End If”处:光标移动到
intNum = CInt(txtInput.Text)中的txtInput.Text上时,弹出提示显示txtInput.Text
的当前值是“10”,这是因为在文本框中输入的内容是10。如图4-10(a)所示。按住鼠标左键选择表达式intNum < 0,并将光
标移到选择的内容上,则弹出提示显示表达式intNum < 0的当前值为False,这是因为intNum的当前值是10。如图4-10
(b)所示。如果光标停留在某一对象变量上时,则通过提示左侧的“+”可以展开显示该对象变量的属性值。如把光标移动到ByVal sen
der As System.Object中的sender上时,弹出的提示如图4-11所示,这是因为sender是当前Button按
钮对象。注意:程序运行暂停位置之前的语句是已经执行的语句,而其后的语句可能没有被执行,因此程序调试时查看变量的值要考虑到语句执行与
否。比如当上述程序运行暂停在If Not (IsNumeric(txtInput.Text)) Then语句处,实时查看语句int
Num = CInt(txtInput.Text)中的txtInput.Text的值为“10”,但intNum的值为0,这是因为还
没有执行类型转换CInt操作和赋值操作。⑵ 在快速监视对话框中查看:当程序暂停在指定的语句处,当光标处在程序中有效的变量上时,按快
捷键Shift+F9,或单击鼠标右键,在弹出菜单中选择“快速监视”,或选择菜单“调试|快速监视”,则弹出快速监视对话框,并显示光标
所在位置变量或表达式的当前值。例如:当程序运行暂停于图4-10所示的“End If”处:光标处在intNum = CInt(txt
Input.Text)语句中的intNum上,按快捷键Shift+F9弹出快速监视对话框,如图4-12(a)所示。可以看到监视列表
中intNum的当前值为10,类型为Integer。还可以在表达式下拉列表框中输入测试表达式intNum<0,单击“重新计算”按钮
,则在监视列表中显示表达式的内容,以及测试结果,如图4-12(b)所示。如果要在监视窗口中实时监视intNum的值或表达式intN
um<0的值,可以单击“添加监视”按钮把intNum或表达式intNum<0添加到监视窗口的监视列表中。可以在快速监视对话框中修改
变量的值,例如在图4-12(a)中,把intNum的值改为1,然后关闭快速监视对话框。按快捷键F5执行剩余的语句,则弹出如图4-1
3所示的对话框。很明显,结果不是1到10的累加结果,而是在文本框中输入1后执行显示的结果。⑶ 在监视窗口中跟踪变量的值:当程序暂停
在指定的语句处,当光标处在程序中有效的变量上时,单击鼠标右键,在弹出菜单中选择“添加监视”,则在监视窗口中显示该变量及其值和类型。
例如:当程序运行暂停于图4-10所示的“End If”处,可以把intNum,intSum添加到监视窗口中,如图4-14所示。如果
按F8逐语句执行,可以看到随着执行的进行,监视窗口中变量的值随之改变。同快速监视对话框,在监视窗口中也可以改变变量的值,如将int
Num的值改为1,则程序运行结束后,其结果同样如图4-13所示。图4-14 在监视窗口中跟踪变量的值⑷ 通过即时窗口输出变量或表
达式的值:在即时窗口中输出变量或表达式的值时使用“?”即可。例如,按快捷键F8逐步执行“累加数”程序,在执行intNum = CI
nt(txtInput.Text)语句之前,在即时窗口中输入:? intNum,则显示intNum的值是0,当执行完intNum
= CInt(txtInput.Text)语句之后,再在即时窗口中输入:? intNum,则显示intNum的值是10。如图4-1
5所示。还可以在即时窗口中输出表达式的值,例如 ? intNum<0。4.2.4 调试程序示例下面讨论例4.1的调试过程。对于例4
.1的调试,我们只讨论两个方面的问题:一是当输入非数字字符时,程序能够识别并能给出响应;二是输入一个整数(正整数或负整数),能够计
算出正确的累加和。⑴ 运行“累加数”程序,在文本框中输入“1a0”,单击“累加”按钮,则程序提示错误信息,如图4-16所示。⑵ 调
试“累加数”程序能否计算出正确的累加和。如果在文本框中输入100,计算1+2+ … +100,计算结果是5151,如图4-6所示。
那么,该结果是否正确?可以在监视窗口中添加intNum、intSum和intCon变量,通过逐语句执行,跟踪intSum和intC
on的值的变化情况,如果跟踪到程序计算累加和时,intCon的值是从1递增到100,而且每次递增的值和intSum累加后递增的值是
一样的,则可以说上述计算结果是正确的。但如果逐语句执行“累计数”程序,在循环累加部分要循环100次,而且每次循环都要查看intSu
m和intCon值的变化情况,非常繁琐!事实上,对于例4.1,我们可以采用更简洁的办法测试结果是否正确:① 如果计算1累加到1的结
果正确(累加结果应该是1);② 如果计算1累加到2的结果正确(累加结果应该是3);③ 如果上述两个结果有一个不正确,则用该程序计算
1累加到100的结果可能不正确!如果上述两个结果都正确,根据归纳法,计算1累加到100的结果也应该是正确的。为此,在文本框中分别输
入1和2,计算累加的结果。如图4-17所示。很明显,结果不正确!这说明该程序的算法有错误,或程序中存在逻辑错误!下面通过逐语句执行
,通过跟踪变量值的变化查找程序中的错误:① 按快捷键F8逐步执行“累加数”程序,在文本框中输入2,即计算1+2的值。② 当逐语句执
行到如图4-18(a)所示的语句时,监视窗口中intNum的值变为2,则说明intNum值的读入和转换(intNum = CInt
(txtInput.Text))是正确的。③ 继续执行,在进入Do While循环时,测试循环控制表达式的值,如图4-19所示,结
果是True,说明可以进行循环,这也和监视窗口中变量的当前值是一致的(intCon是0,intNum是2)。④ 继续执行,当执行完
intCon += 1时,监视窗口显示intCon是1;当执行完intSum += intCon时,intSum是1。累加1后的结
果是1,即累加1后的结果是正确的。如图4-20所示。⑤ 继续执行,则从Loop转入到Do While语句处执行,同第③步,测试循环
控制表达式的值是True,继续循环。当逐语句第2次执行到Loop语句时,监视窗口先显示intCon的值从1变为2,然后是intSu
m的值从1变为3。累加2后的结果是3,即累加2后的结果是正确的。如图4-21所示。⑥ 继续执行,则从Loop转入到Do While
语句处执行,同第③步,测试循环控制表达式的值仍然是True,则说明还可以继续循环!当逐语句第3次执行到Loop语句时,监视窗口先显
示intCon的值从2变为3,然后是intSum的值从3变为6。如图4-22所示。可以看出,intSum的值累加了3,综合上述几步
,可以看出intSum的值是1+2+3的值!⑦ 继续执行,则从Loop转入到Do While语句处执行,同第③步,测试循环控制表达
式的值是False,如图4-23所示,退出Do While循环,执行Loop后面的语句。⑧ 继续执行后面的语句,输出intSum的
值,并退出“累加”按钮对应的Click事件响应过程。显示如图4-17(b)的结果。由上述的逐语句执行过程和跟踪intNum、int
Sum和intCon变量值的变化可知,最后输出的累加结果不是要求的1+2的结果,而是1+2+3的结果!其原因是当计算完1+2(即第
⑤步)后,应该在第⑥步退出循环,但该程序没有退出循环,而是又进行了1次累加3的过程。这也就是累加结果不正确的原因所在!如果要在第⑥
步退出循环,则Do While循环表达式的当前值应该为False,但第⑤步执行后,intCon和intNum的值都是2(如图4-2
1),表达式intCon <= intNum的值肯定为True,如果要使Do While循环表达式的值在第⑤步执行后为False,
只能是把表达式改为intCon < intNum。修改控制Do While循环的表达式为intCon < intNum,再重复上述
逐语句跟踪过程,得出1+2的累加结果为3,累加1的结果为1。由于累加到1的结果正确,累加到2的结果正确,根据归纳法,1累加到100
的结果5050也正确!如图4-24所示。提示:在调试程序时,经常选择一些能够容易确定预期结果的特殊测试用例,如上述调试过程中选择累
加到1和累加到2。有时还要选择一些边界数据,比如“累加数”程序中,测试累加到正整数的上界值2147483647。如果把控制Do W
hile循环的表达式改为intCon < intNum后,“累加数”程序可以正确计算所有整数的累加和吗?答案是否!如果在文本框中输
入正整数的上界值2147483647,单击“累加”按钮,则弹出如图4-25所示的异常信息!如果直接运行“累加数.exe”程序,当在
文本框中输入正整数的上界值2147483647,单击“累加”按钮,程序出现系统提示的错误,如图4-26所示,并异常终止执行。在图4
-25中,由监视窗口看出,当intCon的值为65536(即累加循环65536次)时,intSum += intCon产生算术运算
异常,intSum的值成为了负数!因此,累加到1正确,累加到2正确,累加到100正确,并不能说任何数的累加和都正确!也就是说,当累
加数太大时,程序可能会出现异常,不能得到最终结果!为此,为了处理上述算术运算异常的问题,需要在程序中加入对异常的处理。4.3 异常
处理语句异常处理语句的基本格式为:Try 语句块1 Catch e As Exception 语句块2End Try其
中语句块1中是可能出现异常的代码。如果语句块1中的某一条语句在程序执行期间出现异常,则系统抛出该异常,同时终止出现异常的语句到Ca
tch之前的所有语句的执行。抛出的异常由Catch语句捕获,同时和异常对象(e As Exception)一起,指定所捕获的错误信
息。捕获异常后,执行语句块2的内容。如果语句块1在执行期间没有出现异常,则语句块1执行结束后,直接执行End Try后面的语句。例
如:按快捷键F5运行例4.1中的累加数程序,在文本框中输入2147483648,则在进行数据类型转换时出现如图4-27所示的异常。
注意:2147483648超过了正整数的上界值2147483647。即虽然在文本框中输入的2147483648都是数值字符,但转换
时超过了正整数的上界,同样出现异常。如果将读取文本框输入内容部分的代码改为: ''读取输入的内容 Try
intNum = CInt(txtInput.Text) ''把输入的字符串内容转换为Integer数值类型
Catch ex As Exception MessageBox.Show("输入内容出现异
常:" & ex.Message, "错误") End Try按快捷键F5运行例4.1中的累加数程序,再在文本框中输入214
7483648,则弹出如图4-28所示的对话框信息。提示:ex.Message通过异常对象ex获取描述当前异常的消息。还可以通过e
x.ToString()获取当前异常的字符串表示形式,如图4-29所示,“行号 12”表示代码中的第12行出现异常。如果将循环累加
部分的代码改为: ''累加过程 Try Do While intCon < intN
um intCon += 1 ''累加控制变量递增 intSum += intCon ''累加 Loop ''输出累加结果 txtOutput.Text = intSum Catch ex As Exception MessageBox.Show("累加过程出现异常:" & ex.ToString(), "错误") End Try按快捷键F5运行例4.1中的累加数程序,再在文本框中输入2147483647,则弹出如图4-30所示的对话框信息。4.3.2 处理预期异常如果能够知道在语句块1中可能发生的确切类型的异常,则在Catch语句中直接指定异常的类型,如在例4.1中读取文本框输入内容时,可能出现算术运算异常,则读取文本框输入内容部分的代码可写成: ''读取输入的内容 Try intNum = CInt(txtInput.Text) ''把输入的字符串内容转换为Integer数值类型 Catch ex As OverflowException MessageBox.Show("输入内容出现异常:" & ex.Message, "错误") End Try提示:如果指定具体的异常类型,则在Try语句后可以跟多个Catch语句,用来捕捉不同类型的异常。
献花(0)
+1
(本文系大高老师原创)