您的位置:首页 > 其它

函数复习总结之知识总结

2018-03-22 12:53 190 查看

知识总结:

一.函数的定义
1.函数定义的语法形式
数据类型  函数名(形式参数表)
{
函数体    //执行语句
}
关于函数的定义有如下说明:
     函数的数据类型是函数的返回值类型(若数据类型为void,则无返回值)
     函数名是标识符,一个程序中除了主函数名必须为main外,其余函数的名字按照标
识符的取名规则可以任意选取,最好取有助于记忆的名字
     形式参数(简称形参)表可以是空的(即无参函数),也可以有多个形参,形参间用逗
号隔开,不管有无参数,函数名后的圆括号都必须有。形参必须有类型说明,形参可以是变
量名、数组名或指针名,它的作用是实现主调函数与被调函数之间的关系。
     函数中最外层一对花括号“{}”括起来的若干个说明语句和执行语句组成了一个函
数的函数体。由函数体内的语句决定该函数功能。函数体实际上是一个复合语句,它可以
没有任何类型说明,而只有语句,也可以两者都没有,即空函数
     函数不允许嵌套定义。在一个函数内定义另一个函数是非法的,但是允许嵌套
使用
函数在没有被调用的时候是静止的,此时的形参只是一个符号,它标志着在形参出现的
位置应该有一个什么类型的数据。函数在被调用时才执行,也就是在被调用时才由主调函
数将实际参数(简称实参)值赋予形参。这与数学中的函数概念相似,如数学函数:
f(x)=x^2+x+1
这样的函数只有当自变量被赋值以后,才能计算出函数的值。
2.函数定义的例子
定义一个函数,返回两个数中的较大数
int max(int x,int y)
{
return x>y?x:y;
}
该函数返回值是整型,有两个整型的形参,用来接受实参传递的两个数据,函数体
句是求两个数中的较大者并将其返回主调函数
3.函数的形式    函数的形式从结构上说可以分为三种:无参函数、有参函数和空函数。它们的定义形式都相同
二、函数的声明和调用
1.函数的声明
    调用函数之前先要声明函数原型。在主调函数中或所有函数定义之前,按如下形式声明:
类型说明符   被调函数名(含类型说明的形参表);
    如果是在所有函数定义之前声明了函数原型,那么该函数原型在本程序文件中任何地
方都有效,也就是说在本程序文件中任何地方都可以依照该原型调用相应的函数。如果是
在某个主调函数内部声明了被调用函数原型,那么该原型就只能在这个函数内部有效
   下面对js()函数原型声明是合法的。
    int js (int n);
也可以:
    int js (int);
可以看到函数原型声明与函数定义时的第一行类似,只多了一个分号,成为了一个声明
语句而已。
2.函数的调用
    声明了函数原型之后,便可以按如下形式调用函数:
函数名(实参列表)
    实参列表中应给出与函数原型形参个数相同、类型相符的实参。在主调函数中的参数
称为实参,实参一般应具有确定的值。实参可以是常量、表达式,也可以是已有确定值的变
量、数组或指针名。函数调用可以作为一条语句,这时函数可以没有返回值。函数调用也可
以出现在表达式中,这时就必须有一个明确的返回值
3.函数的返回值
    在组成函数体的各类语句中,值得注意的是返回语句 return。它的一般形式是:
    return(表达式);
    其功能是把程序流程从被调函数转向主调函数并把表达式的值带回主调函数,实现函
数的返回。所以,在圆括号表达式的值实际上就是该函数的返回值。其返回值的类型即为
它所在函数的函数类型。当一个函数没有返回值时,函数中可以没有 return语句,直接利用
函数体的右花括号“}”,作为没有返回值的函数的返回。也可以有 return语句,但 return后
没有表达式。返回语句的另一种形式是:
    return;
这时函数没有返回值,而只把流程转向主调函数。
三、函数的传值调用
    函数传值调用的特点是将调用函数的实参表中的实参值依次对应地传递给被调用函数的
形参表中的形参。要求函数的实参与形参个数相等,并且类型相同。函数的调用过程实际上是对栈空的操作过程,因为调用函数是使用栈空间来保存信息的。函数在返回时,如果
有返回值,则将它保存在临时变量中。然后恢复主调函数的运行状态,释放被调用函数的栈
空间,按其返回地址返回到调用函数
   在C++语言中,函数调用方式分传值调用和传址调用
1.传值调用
这种调用方式是将实参的数据值传递给形参,即将实参值拷贝一个副本存放在被调用
函数的栈区中。在被调用函数中,形参值可以改变,但不影响主调函数的实参值。参数传递
方向只是从实参到形参,简称单向值传递。举个例子:
#include<iostream>
using namespace std;
void swap(int a,int b)
{
int temp=a;a=b;b=temp;
}
int main()
{
int c=1,d=2;
swap(c,d);
cout<<c<<' '<<d<<endl;
return 0;
}   //程序输出为1 2
    在此例中,虽然在swap函数中交换了a,b两数的值,但是在main中却没有交换。因为swap函数只是交换c,d两变量副本的值,实参值没有改变,并没有达到交换的目的
2.传址调用
    这种调用方式是将实参变量的地址值传递给形参,这时形参是指针,即让形参的指针指
向实参地址,这里不再是将实参拷贝一个副本给形参,而是让形参直接指向实参,这就提供
了一种可以改变实参变量的值的方法。现在用传址调用来实现swap:
#include<iostream>
using namespace std;
void swap(int &a,int &b)
{
int temp=a;a=b;b=temp;
}
int main()
{
int c=1;d=2;
swap(c,d);
cout<<c<<' '<<d<<endl;
return
在此例中,因为swap函数的参数为传址调用,&a是指实参变量的地址值传递给形参,所以在函数swap中修改a,b的值相当于在主函数main中修改c,d的值四、全局变量、局部变量    在函数外部定义的变量称为外部变量或全局变量,在函数内部定义的变量称为内部变量或局部变量1.全局变量    定义在函数外部没有被花括号括起来的变量称为全局变量,全局变量的作用域是从变量定义的位置开始到文件结束,由于全局变量是在函数外部定义的,因此对所有函数而言都是外部的,可以在文件中位于全局变量定义后面的任何函数中使用使用全局变量的说明    在一个函数的内部,即可以使用本函数定义的局部变量,也可以使用在此函数前定义的全局变量    全局变量的作用是使得函数间多了一种传递信息的方式。如果在一个程序中多个函数都要对同一变量进行处理,即共享,就可以将这个变量定义成全局变量,使用非常方便,但副作用也不可低估    过多地使用全局变量,会增加调试难度。因为多个函数都能改变全局变量的值,不易判断某个时刻全局变量的值
    过多地使用全局变量,会降低程序的通用性。如果将一个函数移植到另一个程序中,需要将全局变量一起移植过去,同时还有可能出现重名问题。
    全局变量在程序执行的全过程中一直占用内存单元。
    全局变量在定义时若没有赋初值,其默认值为0。
2.局部变量
     (1)局部变量的作用域是在定义该变量的函数内部。换句话说,局部变量只在定义它的
函数
4000
内有效。函数的形参也是局部变量。局部变量的存储空间是临时分配的,当函数执行
完毕,局部变量的空间就被释放,其中的值无法保留到下次使用。
     (2)由于局部变量的作用域仅局限于本函数内部,所以,在不同的函数中变量名可以相
同,它们分别代表不同的对象,在内存中占据不同的内存单元,互不干扰。
     (3)一个局部变量和一个全局变量是可以重名的,在相同的作用域内局部变量有效时全
局变量无效,即局部变量可以屏蔽全局变量。
     (4)在代码块中定义的变量的存在时间和作用域将被限制在该代码块中。如for(inti;
i<=n;i++){sum+=i}中的i是在该for循环语句中定义的,存在时间和作用域只能被
限制在该for循环语句中。
     (5)这里需要强调的是,主函数main中定义的变量也是局部变量,这一点与其他程序设
计语言不同。
     (6)全局变量数组初始全部为0,局部变量值是随机的,要初始化初值,局部变量受栈空
闯大小限制,大数组需要注意。通俗说,局部变量的数组不能开很大,全局变量随便。五、递归函数

        递归函数是一个直接或间接调用函数自身的嵌套型函数。每一个递归函数都有递推(递的概念)和回推(归的概念)的过程。递推过程是将一个复杂的大问题一步步分解成简单的过程类似的小问题,而回推过程是在递归历史的基础上,从最后的最简单的小问题开始,结合该层上一层的输入参数与输出结果,按逻辑一步步向上恢复成最初的复杂的大问题。下面用一个阶乘的例子说明。


递推过程:
(1) 执行A即初始化result=0,通过条件判断执行C,即result = 4*factorial(3);
(2)进入factorial(3),同样先执行A,同样通过条件判断执行C,即result=3*factorial(2);
(3)再进入factorial(2),执行A,然后C,即result=2*factorial(1);
(4)再进入factorial(1),执行A,然后C,即result=1:factorial(0);
(5)再进入factorial(0),先执行A,条件判断执行B,即result = 1;由于if语句后面只有return语句,则执行return语句,即return 1。
至此,因为factorial函数不能再次调用自己了,说明递推部分结束了。由此可见,递推部分是一个分解问题的过程,每一次调用自身,都会重新初始化,重新为形参n开辟内存空间。而整个问题按逻辑和先后顺序被分解成result = 4*3*2*1*1,其中最后的1是factorial(0)返回的
d26c
值。由于使用了return语句,表示最后一个递推函数已经执行完毕,下面开始一步步往上回推。
回推过程:
(a)从递推部分的(5)开始,由于return1,将返回值带入(4),返回主调函数factorial(1),即factorial(1)=1*factorial(0)=1*1=1,由于C语句后面只有return语句,则return 1;
(b)将(4)返回的值带入(3),返回主调函数factorial(2),即factorial(2) = 2*factorial(1)=2*1=2,然后同理执行return 2;
(c)将(3)返回的值带入(2),返回主调函数factorial(3),即factorial(3)=3*factorial(2)=3*2=6,然后return 6;
(d)将(2)的返回值带入(1),返回主调函数factorial(4),即factorial(4)=4*factorial(3)=4*6=24,然后return 24。
至此,已经满足了main函数中输出factorial(4)的要求,且已经到了回推的最顶层,回推结束,返回主调函数main()。从上述描述来看,回推是一个不断返回主调函数的过程,先解决最底层Level d的函数,然后再利用该层的输出值result(不一定是return值,任何在函数运行中被调用到的处于最后状态的值都算是输出值),返回到其主调函数level c中。需替换,要注意的是,在level c函数中,除了调用自身的部分可以用level d的输出值result外,其余的变量还都是level c以前的变量和值。依次类推,不断的返回到上一层主调函数,直到最后的main函数。按照逻辑,回推过程是通过不断解决一个大问题的各个小问题来达到解决大问题的目的,其解决问题的先后顺序为factorial(4) = 1*1*2*3*4,第一个1是factorial(0)的返回值。
按照上面的理论,递推相当于一个不断输入的过程,而回推相当一个反向输出的过程,这样,一个递归函数就是将最先输入的问题最后输出,第2先输入的问题第2后输出,是不是像栈呢?没错,递归函数就是在栈空间内完成的,所以遵循先进后出的原则。每一次调用自身,都是一个输入过程,每一次调用return都是开启一个不间断的输出过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: