{
int i,product=1; for(i=l;i<=n;i++) product*=m: returnCproduet); )
执行该程序输出结果如下:
sum of 4th powers of integers from 1 to 6=2275 说明:
(1)该程序由main ( ) ,sum-of-powers)和powers)三个函数组成,main ( )中调用sum-
of-powers ( )函数,该函数返回一个int型数值,而sum-of-powers ()函数中又调用powers ( )函数,该函数也返回一个int型数值。从中可见,函数之间的嵌套调用在实际编程中是经常使用的。
(2)在主函数中,调用,sum-of-powers ( )函数时,实参是两个符号常量K和N.可见符号常量与一般常量一样都可作为函数的实参。本程序中的两次函数调用都属于传值调用,硒数之间的信息传递是通过返回值来实现的。
5.3.5 函数的递归调用
c语言中允许使用函数的递归调用,这是C语言的又一特点。所谓函数的递归调用是指在调用一个函数的过程中出现直接地或间接地调用该函数自身。例如,在调用f1()函数的过程中,又出现了调用f1()函数,这称为直接调用;而在调用fl()函数过程中出现了调用f2()函数,又在调用f2()函数过程中出现了调用f1()函数,这称为间接调用。 1.递归调用的特点
实际中不是所有的间题都可以采用递归调用的方法。只有满足下列要求的问题才可使用递归调用方法来解决:
能够将原有的问题化为~一个新的问题,而新的问题的解决办法与原有问题的解决办法相同,按这一原则依次地化分下去,最终化分出来的新的问题可以解决。
实际中有意义的递归问题都是经过有限次数的化分,最终可获得解决。这是有限递归问题,而那些无限递归问题在实际中是没有意义的。下面举一个有限递归的例子。例如,求5!由于5!可以化为5*4!.而4!又可化为4*3!,而3!可化为3,2!,而2:可化为2*1!,最后,1!可化为1* 0!,而0!是已知的,即为1.于是,可知5!等于5*4*3*1*1即120.这是一个简单的典型的递归调用的例子。
使用递归调用方法编写程序简洁清晰,可读性强。因此,人们都喜欢用递归调用的方法来解决某些问题。但是,用这种方法编写的程序执行起来在时间和空间的开销上都比较大,即要占用较多的内存单元,又要花费很多的计算时间。因为递归调用时要占用内存的许多单元存放\递推\的中间结果,较复杂的递归占用内存空间较多。因此,在一些内存小速度慢的小机器上最好不要采用递归调用的办法,不然,效率很低。一般的凡是可用递归调用方法编写的程序都可以用迭代的方法来编写。一般说来,相同的间题用迭代方法编写要比用递归调用方法编写的源程序长些。 2.递归调用的过程
递归调用的过程可分为如下两个阶段:
第一阶段称为\递推\阶段:将原问题不断化为新问题,逐渐从未知的向已知的方向推测,最终达到已知的条件,即递归结束条件。 第二阶段称为\回归\阶段:该阶段是从已知条件出发。按\递推\的逆过程,逐一求值回归,最后到递推的开始之处,完成递归调用。可见,\回归\的过程是\递推\的逆过程。
下面以求5!为例写出递归调用的全过程如下所示:
从上述列举的递推过程中可以看出,有实际意义的递归应该是有限的,即递推若干次后。将出现已知条件。并且每递推一次都是向已知条件接近一步。这里的已知条件就是递推结束条件。上例中,0!=I是已知条件,即递推结束条件。在回归的过程中,是按照递推的逆过程进行的,最后得到原问题的解。
[例5.9」用递归调用方法编程求某个正整数的阶乘。 程序内容如下: main () { int n;
scant(\);
printf (\(n)); } fac(n)
int n { int p;
if(n==O) p=1; else
p=n*fac(n一1); return (p);
执行该程序,从键盘上输入一数后,输出结果如下: 5 120
说明:该程序由主函数main)和fac()函数组成,fac<)函数中采用了递归调用的形式,即在fac(n)函数中调用fac(n-1).该递归结束条件时,n等于0,P值为1,每递归一次n减1,经过若干次递归后,n会为0。
[例5.10」汉诺(Hanai)塔间题。这是一个典型的递归调用问题。该问题描述如下:在一张桌子上有A,B,C三处,在A处有n个盘子,每个盘子大小不等,大的在下小的在上。要求将A处的n个盘子移到C处,可以借助于B处,每次移动只允许动一个盘子,在移动过程中在A,B,C三处都应保持大盘在下,小盘在上。编程打印出移动的过程。