欢迎来到学术参考网

在TC++ 3.0集成环境下程序的动态调试

发布时间:2015-12-14 13:49

摘 要:调试程序对程序员而言是一项基本功。然而调试方法的选择和运用,却反映出一名程序员的能力和水平。本文以作者的实际教学经验为基础,对C语言程序设计中常见的错误进行了归纳,并根据实例介绍了在TC++ 3.0集成环境下C程序的动态调试方法。

关键词:调试程序;程序员;动态调试
  任何人在进行程序设计时,错误的出现可以说几乎是不可避免的。也没有人能敢说他编的程序是百分之百完美的。如此一来,程序调试也就很自然的成为程序设计过程中了极其重要的一个环节。如何快速准确地发现并改正错误,正是本文所要探讨和解决的问题。
  一、程序设计中常见的错误
  程序设计是一项展示个性和才华的活动,它既反映出程序员的思维特征,同时也要求其能手脑并用地完成程序整个的开发过程。但是我们经过分析之后不难发现,在程序设计过程中出现的错误有很大的共同点,一般来讲,常见的错误类型可以归纳为以下几点:
  1.设计思路错误:这既可能是算法错误,也有可能是功能上的缺陷。
  2.语法错误:这是初学者特别容易犯的错误。
  3.书写错误:这种错误所造成的危害可大可小,要想在程序设计中避免这种错误的出现,恐怕我们能做的就只有细心、细心、再细心。
  4.输出格式错误:任何一个符号的错误都将导致最终输出结果的错误,这也是最致命的。
  5.其它编程时易犯的错误:①忘记定义变量;②中间运算越界;③变量未赋初值;④If-Then-Else语句混乱;⑤局部变量与全局变量同名造成概念混乱;⑥未注意int型数据的数值范围; ⑦误把“=”作为“等于”运算符;⑧混淆字符和字符串的表示形式;⑨在定义数组时,将定义的“元素个数”误认为是“可使用的最大下标值”等等 。
  二、解决的办法
  既然错误的出现不可避免,那么在程序设计时对程序进行调试也就是很自然的事情了。程序调试的方法主要有静态查错和动态调试。
  静态查错是指在不执行程序的情况下,仅根据程序和框图对求解过程的描述来发现错误。对于前面提到的一些错误比如语法错误、书写错误等在静态查错时一般比较容易被发现。而动态调试则是通过跟踪程序的执行过程,核对输出结果是否正确来发现错误。在程序设计时,有很多潜在的错误在静态查错时可能不容易被发现,但如果采取动态调试的方法对程序进行测试分析就能够很快地发现问题所在并及时纠正。我们重点讨论的是在TC++ 3.0集成环境下程序动态调试的常用方法。
  在TC++ 3.0集成环境下程序动态调试常用的方法有Trace into和Add Breakpoint。其中Trace into是Run菜单的子项,Add Breakpoint是Debug菜单的子项。Trace into(F7),也称作单步执行。Trace into可以进入到过程(函数)内部一步步执行,跟踪程序的每一步执行的过程。对于一些相对较短的程序,程序员可以通过设置变量(Ctrl+F7),每按一次F7,程序执行一行就停下来,然后就通过Watch窗口一一检查变量,直接定位错误。而Add Breakpoint,即设置断点,则可以在一个较长的程序中通过设置若干断点(Ctrl+F8),让程序执行(Ctrl+f9)到断点时即暂停,程序员可以检查此时有关变量和表达式的值,以找到错误所在。下面我们以实例来对这几种方法进行讨论。
  1、要求从键盘上输入N,计算并输出N!
  这是一个很简单的C语言程序。但是在实际的作业练习时,有很多初学者会给出以下程序设计:
  #include
  void main()
  {  int n,y;
      printf(""ninput a inteager number:n"");
      scanf(""%d"",&n);
      y=ff(n);
      printf(""%d!=%d"",n,y);
  }
  int ff(int n)
  {  int f;
      if(n<0) printf(""n<0,input error"");
      else if(n==0n==1) f=1;
      else f=ff(n-1)*n;
      return(f);
  }
  咋眼一看,这个程序似乎没有任何语法和书写错误,也不存在格式输出错误,算法设计也是正确的,甚至即使在程序测试时,只要从键盘上输入的整数n值不大于7,程序的结果都是正确的。但是一旦输入的整数n值超过7,结果就会出错,有很多同学始终弄不明白其中的原因。这时,最好的办法就是采用Trace into的方法按以下步骤对程序进行调试。
  (1)按F7键,可以看到在编辑窗口的源程序中主函数void main()外用高亮度显示,表示准备进入main函数。同时可以选择Window菜单的Watch选项,显示Watch窗口,作为观察数据时用的,见下图。

  (2)连续按F7,只到切换到用户屏,按照提示输入一个整数(为了便于发现错误,我们输入8)后回车,回到编辑窗口。
(3)再按一次F7,程序执行函数调用,进入ff函数体,这时我们可以按下Ctrl+F7组合键,进入Add watch窗口设置观察变量,输入完成后,点击OK按钮即可。
  重复三次,分别设置观察变量n,y,f。
  (4)然后连续按F7,仔细观察变量n,y,f的变化。直到n的值为7,f的值为5040。
  我们注意到:此时函数ff递归调用计算n=7时的阶乘,f的值为5040,即7!,是正确的。然而,当我们再连续按两次F7,就会出现n的值为8,f的值为-25216。
  显然,此时程序出现了问题。因为当n=8时,n!应该为40320,而不是屏幕上显示的-24216。分析原因,我们不难发现,错误出现在对int类型数据的值域认识上,我们知道在16位字长的机器上,基本整型的长度也为16位,因此表示的数的范围也是有限定的。十进制无符号整常数的范围为0~65535,有符号数为-32768~+32767。很明显,40320超出了-32768~+32767的范围,只需重新将相关的位置进行修改即可。
  2、求解一元二次方程的根。程序如下:
  #include
  #include
  void main()
  { float a,b,c,disc,x1,x2,realpart,imagpart;
   scanf(""%f,%f,%f"",&a,&b,&c);  /*从键盘输入a,b,c的值*/
   printf(""The equation"");
   if(fabs(a)<=1e-6)
    printf("" is not a quadraticn"");  /*当a=0时此表达式不是一元方程*/
   else
   { disc=b*b-4*a*c;          /*disc为判别式的值*/
    if(fabs(disc)<=1e-6)
    printf("" has two equal roots:%dn"",-b/(2*a));/*disc等于0,方程有等根*/
    else
    if(disc>1e-6)            /*disc大于0,方程有两不等实根*/
     { x1=(-b+sqrt(disc))/(2*a);    
     x2=(-b-sqrt(disc))/(2*a);
      printf("" has distinct real roots:%d and %dn"",x1,x2);
      }
    else              /*disc小于0,方程有两虚根*/
      { realpart=-b/(2*a);
     imagpart=sqrt(-disc)/(2*a);
     printf(""has complex roots:n"");
     printf(""%d+%din"",realpart,imagpart);
     printf(""%d-%din"",realpart,imagpart);
      }
    }
  }
  在TC下编辑完成之后,对以上程序进行编译,连接都没有问题,然后按Ctrl+F9运行程序,按照提示输入a、b、c的值1、5、4,在结束运行后,用Alt+F5观察用户屏,发现输出为:The equation has distinct real roots:0 and 0。结果显然是错误的。这是让很多人头疼的事情,编译、连接都通过了,而在程序运行时结果却显然是错误的。为了找出问题出现在哪里,我们可以采取以下措施:
  (1)在程序中第14行、第20行、第29行和第32行设置断点:把光标先后移动到这四行,并按下Ctrl+F8键,这四行就被红色条覆盖,同时采用例1中的方法设置观察变量a、b、c、disc、x1、x2、realpart、imagpart,如下图:

  (2)按Ctrl+F9运行程序,执行到scanf函数语句时,切换到用户屏,按照提示输入a、b、c的值1、5、4 ↙ ,程序执行到第二个断点行暂停。(注意:①第一个断点行只有在disc等于0的情况下才会被执行;②此时第二个断点行并未被执行)通过watch窗口查看变量的值,在watch窗口可以看到a、b、c、disc、x1、x2的值分别为1、5、4、9、-1.0、-4.0。显然这是正确的,也就是说程序在disc>0的情况下,计算结果是正确的,到此为止,并没有发现错误。再按Ctrl+F9使程序继续运行,到第四个断点暂停,即程序最后的一个大括号--程序的末尾。此时再观察变量的值,仍然没有错误,但是为什么用户屏上的结果会出错呢,仔细分析之后,我们发现问题出现在输出格式上,disc、x1、x2、realpart和imagpart都是实数,而在输出时使用的是%d格式符,所以出现了错误。将程序中的printf函数中的%d全部改为%f,再运行程序,即可得到正确的输出结果:The equation has distinct real roots:-1.000000 and -4.000000。
  三、小结
  在此,我们只讨论了两种在TC++ 3.0集成环境下程序的动态调试的方法。事实上, TC++ 3.0还提供了许多的调试工具,例如Run菜单中的Step over和Trace into,以及Debug菜单中的Evaluate/modify等等,这些都是在程序调试时很有用的工具,值得大家一起研究。
参考文献:
[1]谭浩强.C程序设计(第三版).清华大学出版
[2] 孟庆昌 牛欣源.C语言程序设计上机指导习题解答.人民邮电出版社
[3] 李玲等.C语言程序设计教程习题解答与实验指导.人民邮电出版社

上一篇:有关PLC发展趋势的研讨

下一篇:计算机技术在建筑防火安全管理工作中的应用