程序的调试
我们在编程时难免都会出错,出错以后怎样找出错误的地方就变得很重要了,只有正确找出错误的地方才可以将其改正,下面我们就谈一些查错的常用方法。
一、如果在我们程序中有语法性的错误,当程序运行到错误的语句时系统就会停下来,并提示我们程序有错,往往还会说出是什么错误,如“命令中含有不能识别的短语或关键字”,并给出选择“取消”、“挂起”、“忽略”、“帮助”四个选择,它们的意思分别是:
取消——中止程序运行,回到命令窗口,相当于执行了cancel命令,在程序中创建的所有变量被释放(除公共变量),但数据库及数据表一般保持当时的状态,您可以用browse命令查看数据表的内容即记录指针所在的位置等等;
挂起——暂停程序,相当于执行了suspend命令,这时程序中的所有变量都保持原值,您可以用?命令查看变量的值,当然也可以查看数据表的情况;
忽略——忽略所出现的错误,即跳过出错的语句继续执行后面的语句;
帮助——显示有关出错的帮助信息,对于错误做更详细的说明。不过很多时候都没什么帮助。
如果这时您一眼就能看出问题出在哪,那么您可以用取消,然后进到程序中找出错误所在,将其改正。在选择了取消后,可能这时有表单是打开的,那么用鼠标点一下该窗口,然后调菜单上的文件—关闭。如果菜单是您自己的自定义菜单,用set sysmenu to default回到系统菜单。改完后,再次运行程序前,最好将所有的数据库及表关闭,以免在程序打开一个数据表时出现表已打开的错误,比较好的办法是在程序开头先关闭所有的数据库及表。关闭所有数据库的命令是:close databases all,关闭所有表的命令是:close tables all。
如果您不知道问题出在程序的哪个地方,那么就选择挂起,系统会弹出一个调试器窗口显示出错的语句,如图1(看上去有点头大吧),在跟踪窗口的黄色箭头所指的语句就是出错的语句。这时不要马上改程序,因为程序还没有结束运行,如要改程序应先终止程序运行,按调试中的终止按钮,然后退出调试器(菜单上的文件—退出),接下来与上面选择取消后的处理方法相同。
一般不要选择忽略,因为程序中上下语句都有很紧密的关系,当一条语句出错后,如果继续运行,可能会出现很多错误,而后面出错的语句可能并没有错,是因为前面错了才导致后面的语句出错,如果前面正确,后面也会正确,因此对于初学者来说,选择忽略不利于找出错误所在。
二、有些时候,程序中的语句并没有出错,但是运行的结果却不是我们所要的结果,这往往是因为我们用错了语句,虽然语句本身是正确的,但用在了不该用的地方、或者该用的地方没有用、又或者语句的先后顺序错了等等,都可能导致这种情况。一旦出现这种情况往往比上一种情况麻烦些,不容易一下看出问题出在哪里,那么需要我们仔细分析程序中的语句,看是否用的对,是否达到了我们的要求。
比如在我们前面的人事管理程序中,调出编辑人员表单,按了新增后,表单中的各控件的内容没有变,那么这就有两种可能,一是没有增加一条空记录,二是没有将控件刷新,这就要我们根据具体问题具体分析。
有时光看语句,怎么也看不出问题在哪,这就用采用一些辅助手段,最常用的辅助手段是在可能发生问题的地方将程序挂起,即在程序中加一句suspend,当程序运行到这里时将程序挂起,然后在命令窗口中查看各有关变量的值或数据表的情况。比如上面的错误,我们可以在新增按钮的click事件的结尾加一句suspend,当程序运行到这里时就会挂起,我们可以用browse查看数据表,如果发现里面没有一个空记录,那么说明漏了加空记录的语句。如找到错误了,记得在命令窗口中运行cancel,将程序终止再去修改程序。
另外在程序挂起时我们可以调出器,看程序执行到什么地方,调的方法是在菜单上的工具—调试器,可以在其中的监视窗口查看各表达式的值,在局部窗口查看各变量的值,而且您可以在窗口中长条文本框中输入一个表达式或变量,调试器会显示出它们的值。
如还不能找到问题,按可单步执行程序,即按一下运行一条语句,这样可以更有助于找到问题。至于调试器的其它功能,我们将在以后的课程中讲解。
常见错误
启动一个表单后,再用代表这个表单的变量去调用它时却不行。调用表单的变量与其它变量一样,如是在一个子程序中创建的,当这个程序运行结束后,这个变量也就释放了,即这个变量不再存在了,虽然表单还在,故不能用这个变量去调用该表单了。解决的方法是将其设为公共变量,或在更高层的程序中创建,还可以在调用表单命令中加上“linked”子句(do form...name...linked)。
在表单中的一个事件(如init)中创建了一个变量,但在表单的其它地方却不能使用。一个事件程序相当于一个子程序,当子程序运行完后在其中创建的变量也就没不存在了。解决的方法是将其设为公共变量,或在更高层的程序(如调用表单的程序)中创建。
常常在表格中或其它地方看不到数据表中的记录。这往往是因为记录指针到尾部,即EOF()为真。
修改记录时却个修改了另一个记录。这往往是因为进入修改后又做了查询,查询后没有将记录指针返回到原记录。 进入一个循环后就死机了。这是因为没有设置跳出循环的条件,或者条件永远不能满足,比如一个循环的跳出条件是当一个变量的值达到某一数值,每循环一次应将该变量加1,但忘了加1的语句,就会造成死循环,因为变量的值永远达不到预定的数值。
查询英文时,明明有的记录查不到。这可能是大小写不一样造成的,比如:locate for name='crops',如果数据表中的是“CROPS”那么就查不到。解决的办法:locate for upper(name)='CROPS'。
不管是英文还是中文,还是查不到所要的记录。这种情况很可能是输入的查询值后面有空格,比如还是上面那个查询语句,如果操作者不小心在文本框中输入了“crops_”(下划线代表有一个空格),而这个空格往往是不容易被发现的,那么查询时就可能找不到,除非数据表中的数据也刚好是这样,这里要注意一点一个字符字段的内容如小于字段的长度,系统会自动为该字符后面加上空格,比如上面那个例子,如果name的长度是8,则“crops”这个记录name的值就是“crops___”(后面有三个空格),那么有三个空格和有一个空格的就不相等。解决的办法是用trim()函数将输入的查询值后面的空格去掉,更进一步,为了防止不小心前面也加了空格,可用alltrim()将前后的空格都去掉。
用do form启动一个表单后,应等关闭表单后再执行do form后面的语句,但表单启动后却接着运行后面的语句。这是因为表单的windowtype属性没有设为“1-模式”,解决的办法不用我说了吧。
当在数据表中移动记录指针等操作时出现意想不到的错误。往往是因为没有记录。
按索引查询时找不到所要的记录,当然记录是有的。索引没有及时更新,对于不是用的结构化索引,即所用索引不是在建表时创建的,而是以后用别的文件名创建的索引,不会与数据表一起打开,那么当数据表更新后......,解决的办法想必大伙儿都知道吧。