设为首页 加入收藏

TOP

2.2.2 箱式跟踪
2014-03-11 13:05:09 来源: 作者: 【 】 浏览:148
Tags:2.2.2 箱式 跟踪

2.2.2  箱式跟踪

可以使用箱式跟踪帮助理解递归并调试递归函数。不过,这种机械性策略不能替代对递归的直观理解。箱式跟踪演示编译器如何频繁地实现递归。通过读取下面对该技术的描述可知,各个箱大致对应于一个活动记录,编译器一般在函数调用实现中使用这个活动记录。C++片段2中将进一步讨论活动记录。

注释:活动记录是为函数调用创建的

下面通过递归函数fact讲述箱式跟踪,这个函数返回一个值。

(1) 标记递归函数体中的各个递归调用。一个函数中可能有几个递归调用,所以有必要加以区别。这些标记有助于跟踪在函数调用完成后必须返回的正确位置。例如,用字母A标记函数体内的fact(n-1)表达式。
 

  1. if (n == 0)  
  2. return 1;  
  3. else  
  4. return n * fact(n-1);  
  5. ○A 

每次递归调用后,都会返回点A。用返回值替换fact(n-1),并继续计算表达式n*fact(n-1)。

注释:标记函数内的每次递归调用

(2) 在执行过程中,用一个新箱表示各个函数调用;新箱指示函数的局部环境。具体地讲,每个箱包含:

形参列表中的参数值。

函数的局部变量。

从当前箱的各个递归调用所返回的值的占位符。标记这个占位符,以与第1步中的标记相对应。

函数本身的值。

注释:每次函数被调用的时候,都会用新箱表示局部环境

当第一次创建箱时,只知道输入参数的值,其他值则要根据函数的执行来判断。例如,可以为fact(3)的调用创建如图2-3所示的箱(后面的示例将看到,引用参数的处理方式同值参数和局部变量的处理方式略有不同)。

(3) 绘制一个箭头,从启动递归过程的语句指向第一个箱。接下来,在递归调用后新建一个箱(如第2步所述),绘制一个箭头,从执行调用的箱指向新箱。标记各个箭头,以与递归调用的标记(见第1步)对应;这个标记指示调用完成后准确的返回位置。例如,图2-4显示cout<<fact(3)语句中对fact的调用生成的前两个箱。

(4) 在通过前两步新建箱并绘制箭头后,开始执行函数体。不管当前箱是如何生成的,对函数局部环境中值的引用都对应当前箱中的值。

(5) 在退出函数时,取消当前箱,并沿箭头返回调用该函数的箱。于是,这个箱成为当前箱,箭头上的标记指明了下面将在那个位置执行函数。用刚终止的函数调用所返回的值替换当前箱的对应的占位符。

图2-5显示了调用fact(3)的完整箱式跟踪。在这些顺序图中,当前箱在箭头路径的最深处,并用浅灰色显示;被取消的箱用虚框表示,颜色为深灰色。

提示:箱式跟踪与合适的cout语句配合,可以有效地辅助调试递归函数。这种语句应该报告程序中递归调用发生的位置,以及进入或者退出函数处的输入参数和局部变量的值。在函数的最终版本中一定要记得删除这些语句。

问题2 编写问题1给定函数的箱式跟踪。

 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇2.2.1 递归值函数:n的阶乘(2) 下一篇2.3 执行动作的递归(1)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·HTTPS 详解一:附带 (2025-12-26 02:20:37)
·TCP/IP协议到底在讲 (2025-12-26 02:20:34)
·TCP和UDP在socket编 (2025-12-26 02:20:32)
·有没有适合新手练习 (2025-12-26 01:48:47)
·用清华镜像网怎么下 (2025-12-26 01:48:44)