C++编程入门系列之九(函数的定义与调用

C++编程入门系列之九(函数的定义与调用)

上一讲鸡啄米给大家讲了自定义数据类型,这一节鸡啄米给大家讲讲编程入门时另一个比较重要的概念,函数。一个复杂的问题往往可以分为若干子问题,然后对每个子问题分别解决。C++和C语言就是用函数来解决子问题的。函数写好以后,可以被重复调用,我们调用时只需要关注它的功能和使用方法,至于它时怎样实现的我们不需要关心。这样有利于代码重用,提高开发效率,便于分工开发和维护。

一个C++程序可以由一个主函数和若干子函数组成,主函数是程序执行的开始点,一般就是main函数,主函数调用子函数,子函数还可以调用其他子函数。调用其他子函数的函数称为主调函数,被其他函数调用的子函数称为被调函数。

1.函数的定义

函数定义的语法形式是:

   类型标识符  函数名(形式参数表)
    {
            语句序列
    }

类型标识符是函数的类型,就是常说的函数的返回值类型。函数的返回值可以返回给主调函数使用,由return语句给出,比如:return 0。没有返回值的函数的类型标识符为void,不需要写return语句。

形式参数简称为形参,形参表的形式如下:type1 name1,type2 name2,…,typen namen。其中,type1,type2,…,typen是类型标识符,表示形参的类型,name1,name2,…,namen是形参名。形参的作用就是实现主调函数和被调函数之间的联系,形参一般是函数需要处理的数据、影响函数功能的因素,没有形参的函数在形参表的位置写void或者不写形参表。

函数在没有被调用的时候形参只是一个符号,它只表示形参的位置应该有一个什么样的数据。函数被调用时才由主调函数将实际参数赋予形参,实际参数通常简称实参。简单说,函数声明时的参数叫形参,被调用时传入的参数叫做实参。

2.函数的调用

a.函数的调用形式

函数调用之前必须先声明函数原型,可以在主调函数中声明,也可以在所有函数之前声明,只要在调用它之前声明就可以。声明形式为:

类型说明符 被调函数名(含类型说明的形参表)

若是在主调函数内部声明了被调函数原型,那么该原型只能在这个函数内部有效,也就是只能在这个函数中调用。若是在所有函数之前调用,则该函数原型在本程序文件中任何地方都有效,也就是在本程序文件中任何地方都可以按照该原型调用相应的函数。

声明了函数原型以后,就可以按如下形式调用子函数:函数名(实参表)。实参表中应该给出与函数原型中形参个数相同、类型相符的实参。函数调用可以作为一条语句,这时函数可以没有返回值;函数调用也可以出现在表达式中用于计算,这时就必须有返回值了。

鸡啄米给大家一个函数调用的例子:

   #include <iostream>
   using namespace std;
   double power(double x, int n);
   int _tmain(int argc, _TCHAR* argv[])
   { 
           cout<<"5 to the power 2 is "<<power(5,2)<<endl;
           return 0;
   }
   double power(double x, int n)
   { 
          double val=1.0;
          while (n--)
                val *= x;
          return(val);
   }
   运行结果是:5 to the power 2 is 25

b.函数调用的执行过程

鸡啄米再跟大家讲下函数调用的执行过程。C++程序经过编译以后生成可执行程序,存在硬盘中,程序启动时首先从硬盘把代码装载到内存的代码区,然后从入口地址也就是main函数的起始处开始执行。程序执行时如果遇到对其他函数的调用,则暂停当前函数的执行,保存下一条指令的地址,也就是返回地址,作为从子函数返回后继续执行的切入点,并保存变量状态等现场,然后转到子函数的入口地址执行子函数。遇到return语句或者子函数结束时则恢复先前保存的现场,并从先前保存的返回地址开始继续执行。

c.函数的嵌套调用

函数允许嵌套调用,如函数1调用函数2,函数2又调用了函数3就形成了函数的嵌套调用。鸡啄米再给大家一个函数嵌套调用的例子:

   #include <iostream>       
   using namespace std;
   int _tmain(int argc, _TCHAR* argv[])
   {
           int a,b;
           int fun1(int x,int y); //在函数中定义函数
           cin>>a>>b;
           cout<<"a、b的平方和:"<<fun1(a,b)<<endl;
           return 0;
   }
   int fun1(int x,int y)
   {
           int fun2(int m);
           return (fun2(x)+fun2(y));
   }
   int fun2(int m)
   {
          return (m*m);
   }

大家可以把这段代码拷到VS2010上运行下,修改再试下,理解理解函数的嵌套调用。

d.递归调用

递归调用就是函数直接或间接的调用自身。调用自身就是指在一个函数的函数体中出现了对自身的调用语句。直接调用自身如:void fun(void) { …; fun(); …}。间接调用自身如:void fun1(void) { …; fun2(); …} void fun2(void) { …; fun1(); …},这里fun1调用了fun2,fun2又调用了fun1,这样就构成了递归。

递归调用就是将原有的问题分解成新的问题,而解决新问题时又用到了原有问题的解法。就这样循环分解下去,直到最终分解出来的问题时一个已知解的问题,这就是有限的递归调用,也才是有意义的,无限的递归调用永远也得不到解,没有实际意义。

递归调用有两个阶段,第一个阶段是递推,将原问题不断分解成新的子问题,逐渐向最终的解推进,最后达到已知的条件,也就是递归结束的条件,递推阶段就结束了。比如,计算4!,可以这样分解递推:

       4!=4×3!→3!=3×2!→2!=2×1!→1!=1×0!→0!=1
   未知------------------------------------------------------->已知

第二个阶段是回归,从已知的条件出发,按照递推的逆过程,逐一求值回归,最后到达递推的开始处,结束回归完成递归调用。还看求4!的例子,回归阶段如下:
4!=4×3!=24→3!=3×2!=6→2!=2×1!=2→1!=1×0!=1→0!=1
未知——————————————————————>已知

鸡啄米举个递归调用的例子:

   分析:计算n!的公式是:n=0时,n!=1,n>0时,n!=n(n-1)!。这是一个递归形式的公式,编程求n!时采用递归算法,递归的结束条件是n=0。程序代码如下:

   #include <iostream>       
   using namespace std;
   long fac(int n)
   { 
            long f;
            if (n<0) 
                    cout<<"n<0,data error!"<<endl;
            else if (n==0) 
                    f=1;
            else 
                    f=fac(n-1)*n;
            return(f);
   }
   int _tmain(int argc, _TCHAR* argv[])
   {
           long fac(int n);
           int n;
           long y;
           cout<<"Enter a positive integer:";
           cin>>n;
           y=fac(n);
           cout<<n<<"!="<<y<<endl;
           return 0;
   }

运行结果:
Enter a positive integer:8
8!=40320

递归算法在编程入门时可能有点难,不好吸收,没关系,现在大家可以先理解下,以后等功力强了回来看下就很容易掌握了。而且递归算法的效率不是很高,能用其他算法尽量用效率高的算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值