C++第二次作业——函数

第二次作业——函数

1.函数的使用

在面向对象的程序设计中,函数是面向对象程序设计中对功能的抽象

Q:函数这么重要,为什么要使用函数呢?

A:一个较为复杂的系统往往需要划分为若干个系统,然后对这些子系统分别进行开发调试。C与C++语言则体现为函数。函数编好后,可以被重复使用,使用时可以只关心函数的功能和使用办法而不必关系函数功能的具体实现,这样有利于代码的重用,可以提高代码效率,增强程序的可靠性,也便于分工合作和修改。

函数的定义:

类型说明赋 函数名(含类型说明的形式参数表)
{
    语句序列
}

形式参数(简称形参)表的内容如下:

type 1 name1,type 2 name 2,…

其中name n是形参名。形参的作用是实现主调函数与被调函数之间的关系。

2.函数重载

两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。

Q:为什么要用这个功能呢?

A:如果没有重载机制,那么对不同类型的数据进行相同的操作也需要定义名称完全不同的函数。实是麻烦。

eg:

int add(int x,int y);
float add(float x,float y); //与上式形参类型不同
int add(int x,int y);
int add(int x,int y,int z); //与上式形参个数不同

注意&习惯:不要将不同功能的函数定义为重载函数,以免出现对调用结果的误解、混淆。

3.函数的值传递

值传递是指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参(直接将实参的值传给形参)。这一过程时参数值的单向传递过程,一旦形参获得了值便于实参脱离关系,此后无论形参发生了怎么样的改变,都不会影响到实参。

Q:举个栗子吧!

A:举一个经典的例子!交换整数!

#include <iostream>
using namespace std;

void swap(int a,int b){
    int t = a;
    a = b;
    b = t;
}
int main(){
    int x=5,y=10;
    cout<<"x="<<x<<"   y="<<y<<endl;
    swap(x,y);
    cout<<"x="<<x<<"   y="<<y<<endl;
    return 0;
}

分析:由于采用的是值传递,函数调用时传递的是实参的值,是单向传递过程,形参的改变对实参不起作用。

4.引用传递

引用是一种特殊类型的变量,可以被认为是另一个别名,通过引用名与通过被引用的变量名访问变量的效果是一样的。

使用引用时必须注意下列问题。

1)声明一个引用时,必须对它进行初始化,使它指向一个已存在的对象。

2)一旦一个引用被初始化后,就不能改为指向其他对象。

Q:和值传递有什么区别呢?

A:我们用代码来证明!

#include <iostream>
#include <iomanip>
using namespace std;

void fiddle(int in1,int &in2){
    in1=in1+100;
    in2=in2+100;
    cout<<"The values are";
    cout<<setw(5)<<in1;
    cout<<setw(5)<<in2<<endl;
}
int main(){
    int v1=7,v2=12;
    cout<<"The values are";
    cout<<setw(5)<<v1;
    cout<<setw(5)<<v2<<endl;
    fiddle(v1, v2);
    cout<<"The values are";
    cout<<setw(5)<<v1;
    cout<<setw(5)<<v2<<endl;
    return 0;
    
}

分析:子函数fiddle的第一个参数in1时普通的int型,被调用时传递的是实参v1的值,第二个参数in2是引用,被调用时由实参v2初始化称为v2的一个别名。于是在子函数中对参数in1的改变不影响实参,而对形参in2的改变实际上就是对住函数中变量v2的改变。因而返回主函数后,v1值没有改变,而v2值发生了改变。

5.递归函数

函数可以直接或间接地调用自身,称为递归调用。

所谓直接调用自身,就是真在一个函数的函数体中出现了对自身的调用表达式。

eg:

void fun1(){
…
fun1(); //调用函数自身
}

递归算法的实质是将原有的问题分解为新的问题,二解决新的问题又用到了原有问题的解法。按照这一原则分解下去,每次出现的新问题都是原有问题的简化的子集,而最终分解出来的问题,是一个已知解的问题。这便是有限的递归调用。只有有限的递归调用才是有意义的。

递归的过程有如下两个阶段:

1)递推

将原有问题不断分解为新的问题,逐渐从未知向已知推进,最终达到已知的条件,即递归结束的条件,这时递归阶段结束。

2)回归

从已知的条件出发,按照递推的逆过程,逐一求值回归,最后大道递推的开始处,结束回归的阶段,完成递归阶段。

Q:用递归知识解决汉诺塔问题。

A:ok👌

分析:将n个盘子从A针移到C针可以分解为下面3个步骤

1.将n个盘子从A针移到B针上(借助C针)

2.把A针上剩下的一个盘子移到C针上

3.将n-1个盘子从B针移到C针上(借助A针)

上面三个步骤包含了两个操作:

1.将多个盘子从一个针移到另一个针上,这是一个递归的过程

2.将1个盘子从一个针上移到另一个针上

用hanoi函数实现操作1,用move函数实现操作2

代码如下:

#include <iostream>
using namespace std;

//src针的最上面一个盘子移动到dest针上
void move(char src,char dest){
    cout<<src<<"-->"<<dest<<endl;
}
//把n个盘子从src针移动到dest针,以medium针作为中介
void hanoi(int n,char src,char medium,char dest){
    if (n==1)
        move(src,dest);
    else{
        hanoi(n-1,src,dest,medium);
        move(src,dest);
        hanoi(n-1,medium,src,dest);
    }
}
int main(){
    int m;
    cout<<"Enter the number of diskes:";
    cin>>m;
    cout<<"the steps to moving"<<m<<" diskes:"<<endl;
    hanoi(m, 'A', 'B', 'c');
    return

posted @ 2019-09-16 21:43  rain-coding  阅读(324)  评论(0编辑  收藏  举报