C++探索之旅第一部分第七课:函数效应,分而治之
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++探索之旅第一部分第七课:函数效应,分而治之相关的知识,希望对你有一定的参考价值。
内容简介
1、第一部分第七课:函数效应,分而治之
2、第一部分第八课预告:传值引用,文件源头
函数效应,分而治之
上一课《【C++探索之旅】第一部分第六课:控制流程,随心所至》中,我们学习了条件语句和循环语句。
这两种语句也算是算法的核心了。在更早的课程中,我们学习了变量。这些都是所有编程语言的必备元素。
这一课我们又要学习一个几乎所有编程语言都有的极重要元素:
函数。
C++的所有程序都或多或少用到函数,到目前为止,你其实也已经用了好多次了,不过你可能只缘身在此山中,还云深不知处。
函数的功用是:
将程序切分成更小的可重用的单元,有点像砖块。一旦砖块制作完毕,程序员所要做的就是用砖块来造东西。
我们砌一堵墙,盖一座小屋,或者摩天大楼,都需要不少砖块。用函数构建我们的程序就似用砖块搭建,而且如果拆除了,之后这些砖块还可以重复使用。
慢慢你就能体会了。编程之美是需要时间去印证的,如果只远观而不"亵玩",没有动手实验,是不能进步的。
首先我们就挽起袖子,和好水泥,来学习如何制作"砖块"(函数)吧。
函数的创建和使用
从这个课程的最初,我们已经使用了函数了。而且到目前为止都是那个函数:main函数(是我,是我,还是我...)。
这是C++程序的入口,程序是从main函数开始执行的。如下所示:
#include <iostream> using namespace std; int main() // main函数开始,程序的开始 { cout << "Hello World !" << endl; return 0; } // main函数的结束,程序也随之结束
以上的程序实际是从第四行开始,在第八行结束。也就是说,此程序的所有动作都是在一个函数里完成的。我们并没有跳转到其他地方,没有出这个main函数,而是按顺序执行main函数中的各句指令。
既然我这样说,聪明如你应该料想到了:我们可以写其他的函数,把一个复杂的程序分割成相对独立的区块。
是的。但是为什么要这么做呢?
虽然说,把所有代码都放在一个main函数里是完全可以的,但这并不是一个好习惯。
假设我们要开发一个大型3D游戏。
大型3D游戏可是很复杂的,代码数动辄上万行。如果我们把这么多代码都一股脑儿放到main函数里,那么是很容易迷失在茫茫码海中的。
比较理想的方式是在某个地方存放一小块代码,比如用于移动人物;另一个地方存放另一块代码,用于加载关卡,等等。
把代码分成函数可以方便管理,使我们的代码更容易被别人理解,我们自己回看时也不至于迷失了方向。
而且,假如你们是好几个程序员一起协同开发,那么函数可以让你们更好地分配工作,比如某个人负责哪些功能开发,就需要写哪些函数。
但这并不是函数的全部益处。
举个例子:我们要计算平方根。上一课我们已经学习了怎么做,我们使用了数学库中的sqrt这个函数。
类似开平方根这样常用的代码块,如果包装成一个函数,那么在不同地方使用时就不需要把相同的代码重新拷贝一次了,只需要写一下函数名就可以了。
所以函数使我们可以重复使用已有的代码块,极大地提高效率。
函数简介
函数包含完成特定任务的一个代码块。它接收需要处理的数据,处理之,然后返回一个值。
可以把函数想象成一台制作香肠的机器,在输入那一头你把猪装进去,输出那一头就出来香肠了。这酸爽。
输入函数的数据称为参数,而函数输出的数据称为返回值。如下图所示:
你是否还记得我们上一课列出的多个数学函数中的pow函数,是用于计算次方值的。例如2的3次方,可以用pow(2, 3)来计算。
如果我们使用刚才所说的专业术语(参数,返回值),那么pow函数的基本介绍可以如下所示:
接收两个参数x和y
进行数学计算(x的y次方)
返回值就是计算结果
如下图所示:
定义函数
好了,该放手一搏了。上面看了一些函数的例子,我们自己来定义一个函数吧。
首先,C++中所有的函数基本都遵循以下模板:
type functionName(arguments)
{
// Body : Instructions
}
上面的是英语的表述法,如果翻成中文就是:
类型 函数名(参数)
{
// 函数体:指令
}
关于这个模板我们需要掌握四点:
函 数类型:对应输出类型,也可以把其看做函数的类型。和变量类似,函数也有类型,这类型取决于函数返回值的类型。如果一个函数返回一个浮点数(带小数点 的),那么自然我们会将函数类型定为float或者double;如果返回整数,那么我们一般会将类型定为int或long。但是我们也可以创建不返回任 何值的函数。
函数名:这是你的函数的名字。我们已经见过不少函数名了,比如main,sqrt,pow。你可以给你的函数起任意名字,只要遵从给变量命名的相同的规则就好。
函数的参数(对应输入):参数位于函数名之后的圆括号内。这些参数是函数要用来做操作(运算)的数据。你可以给函数传入任意数量的参数,也可以不传入任何参数(例如main函数)。
函数体:大括号规定了函数的起始和结束范围。在大括号中你可以写入任意多的指令。
注意:
在 C语言中,同一个程序里不允许同名的函数。但是C++中允许有同名函数,称为函数重载。只需要它们的参数不同(注意是参数不同,如果返回值不同而参数一样 不是函数重载,也不能通过编译)。例如在C++中,int multiplication(int a, int b) 和 double multiplication(double c, double d) 就是不同的函数,尽管它们的函数名一样,但是参数列表不一样。但是如果定义两个函数如下:int multiplication(int a, int b) 和 double multiplication(int c, int d),编译是会出错的,因为它们的参数一样,只是返回值不一样,是不能算不同函数的。
我们自己来定义一个函数:
int addTwo(int number) { int value(number + 2); // 在内存中申请一个int类型的"抽屉",起名叫value // 将参数中接收到的number进行加2操作 // 将加法的结果存入value里面 return value; // 指定value为函数的返回值 }
注意:在参数的那个括号和函数体的大括号后面都没有分号哦!
分析此函数
根据我们之前的解释,你应该明白第一行是干什么了吧。就是定义一个函数,名叫addTwo(英语"加2"的意思),接收一个int型参数作为输入,操作结束之后会返回一个int型值。如下图:
return value; 那一行是什么意思呢?
return是英语"返回"的意思,所以这一行指令的作用就是将value作为此函数的返回值返回。addTwo的参数number就类似之前那个图中放入香肠制造机的猪,value就类似输出的香肠。
value的类型必须是int,因为在函数定义的第一行的返回值类型是int。
函数调用
我们的函数定义完毕,接下来该是使用它的时候了。函数的使用也有一个术语,叫做:函数调用。
#include <iostream> using namespace std; int addTwo(int number) { int value(number + 2); return value; } int main() { int a(2), b(3); cout << "a的值是 " << a << endl; cout << "b的值是 " << b << endl; b = addTwo(a); // 函数调用 cout << "a的值是 " << a << endl; cout << "b的值是 " << b << endl; return 0; }
运行以上程序,显示:
a的值是 2
b的值是 3
a的值是 2
b的值是 4
在调用函数addTwo之后,a的值没有改变;b的值改变了,等于a的值加上2。
详细解释
现在我们来看一个程序,包含一个multipleTwo函数,用于计算一个数的两倍的值。
我们暂时把multipleTwo函数写在main函数之前,如果放在main函数之后会出错,以后的课程我们会解释为什么。
#include <iostream> using namespace std; int multipleTwo(int number) { return 2 * number; } int main() { int initial = 0, twice = 0; cout << "请输入一个整数... "; cin >> initial; twice = multipleTwo(initial); cout << "这个数的两倍是 " << twice << endl; return 0; }
我们的程序是从main函数开始运行的,这个大家已经知道了。
我们首先请求用户输入一个整数,将其值传递给multipleTwo函数,并且把multipleTwo函数的返回值赋给twice这个变量。
仔细看下面这一行,这是我们最关心的一行代码,因为正是这一行调用了我们的multipleTwo函数。
twice = multipleTwo(initial);
在括号里,我们将变量initial当做输入传递给函数,也正是这个变量,函数将其用于内部的处理。
这个函数返回一个值,就是twice这个变量。
其实这一行中,我们就是命令电脑:“让multipleTwo函数给我计算initial的两倍的值,并且将结果储存到twice这个变量中”。
详细的分步解释
也许对于初学者,理解起来还是有些许困难。
不用担心,我相信通过下面的分步解释,大家会明白得更透彻。
这个特殊注释的代码向大家展示了程序的运行顺序:
#include <iostream> using namespace std; int multipleTwo(int number) // 6 { return 2 * number; // 7 } int main() // 1 { int initial = 0, twice = 0; // 2 cout << "请输入一个整数... "; // 3 cin >> initial; // 4 twice = multipleTwo(initial); // 5 cout << "这个数的两倍是 " << twice << endl; // 8 return 0; // 9 }
上面的编号表示了执行的顺序:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
程序从main函数开始执行
在main函数中的命令一行一行地被执行
执行cout输出
执行cin读入数据,赋值给变量initial
读入指令... 调用multipleTwo函数了,因此程序跳到上面的multipleTwo函数中去执行
我们运行multipleTwo函数,并接受一个数作为输入(number)
我们对number做运算,并且结束multipleTwo函数,return意味着函数的结束,并且返回一个值。将返回值赋给twice变量。
我们重新回到main函数的下一条指令,用cout输出
又一个return,这次是main函数的结束,于是整个程序运行完毕。
变量initial被传值给multipleTwo的参数number(另一个变量),称为值传递。当然其实原理是做了一份变量initial的拷贝,把拷贝赋值给了number。
这里如果我们把initial改名为number也是可以的,并不会与函数multipleTwo的参数number冲突。因为参数number是属于multipleTwo这个函数的专属变量。
多个参数
上面的addTwo函数只有一个参数,我们也可以定义有多个参数的函数。其实之前见过的pow函数和getline函数就有两个参数。
int addition(int a, int b) { return a+b; }
double multiplication(double a, double b, double c) { return a * b * c; }
以上所定义的两个函数中,我们合理地偷懒了:将参数运算的结果直接作为返回值,而没有定义例如之前在addTwo函数中用到的value这样的变量。这样我们的代码也达到了最简化,我们是鼓励这样做的。程序员要会"偷懒"。
上面的第一个函数addition(英语"加法,相加"的意思)接收两个int型参数,返回它们的相加值。
第二个函数multiplication(英语"乘法,相乘"的意思)接收三个double型参数,返回它们的相乘值。
我们也可以定义参数类型不一样的函数。例如:double different(int a, double b);
无参数
我们的函数也可以没有参数。那么在括号里就不加任何东西。
例如:
string getName() { cout << "请输入你的名字 : "; string name; cin >> name; return name; }
无返回值的函数
函数也可以没有返回值,那么在定义的时候要将函数返回值类型设为void(英语"虚空,无"的意思)。不用加return语句了。例如:
void sayHello() { cout << "Hello!" << endl; // 因为没有返回值,也就没有return语句了 }
int main() { sayHello(); // 因为函数sayHello不返回任何值 // 我们调用的时候也不会将其赋给某个变量了 return 0; }
实例
下面我们会一起看几个函数的实例,以便读者对函数有更深入的了解。我们尽量展示不同情况,使大家看到可能出现的各种函数类型。
欧元/人民币转换
最近欧元兑换人民币的汇率还是很稳定的在7左右徘徊,为什么当年(2009)小编出来法国时,欧元的汇率那么高(10),现在要换人民币却只有7。唉,就是辣么不逢时。
我们就来写一个函数,用于转换欧元到人民币。
查了一下最新的汇率:
1欧元 = 7.0992 人民币元
#include <iostream> using namespace std; double conversion(double euros) { double rmb = 0; rmb = 7.0992 * euros; return rmb; } int main() { cout << "10 欧元 = " << conversion(10) << "人民币" << endl; cout << "50 欧元 = " << conversion(50) << "人民币" << endl; cout << "100 欧元 = " << conversion(100) << "人民币" << endl; cout << "200 欧元 = " << conversion(200) << "人民币" << endl; return 0; }
你也可以写一个人民币转换为欧元的小程序。
惩罚
接下来看一个函数,这个函数不会返回任何值,所以类型是void。这个函数会根据传入的参数在屏幕上显示一定次数的信息。这个函数只有一个参数,那就是显示惩罚语句的次数:
#include <iostream> using namespace std; void punish(int lineNumber) { int i; for (i = 0 ; i < lineNumber ; i++) { cout << "我不应该有钱任性" << endl; } } int main(int argc, char *argv[]) { punish(5); return 0; }
显示结果如下:
我不应该有钱任性
我不应该有钱任性
我不应该有钱任性
我不应该有钱任性
我不应该有钱任性
矩形面积
矩形的面积很容易计算:长 x 宽。长度乘以宽度。
我们来写一个求矩形面积的函数,它有两个参数:矩形的长和矩形的宽。返回值是矩形的面积:
#include <iostream> using namespace std; double rectangleArea(double length, double width) { return length * width; } int main() { cout << "长是10,宽是5的矩形面积是 " << rectangleArea(10, 5) << endl; cout << "长是3.5,宽是2.5的矩形面积是 " << rectangleArea(3.5, 2.5) << endl; cout << "长是9.7,宽是4.2的矩形面积是 " << rectangleArea(9.7, 4.2) << endl; return 0; }
显示结果:
长是10,宽是5的矩形面积是 50.000000
长是3.5,宽是2.5的矩形面积是 8.750000
长是9.7,宽是4.2的矩形面积是 40.740000
我们可以直接在函数里显示 长,宽和计算所得的面积吗?
当然可以。这样的情况下,函数就不必返回任何值了,函数计算出矩形面积,然后直接显示在屏幕上:
#include <iostream> using namespace std; void rectangleArea(double length, double width) { double area = 0; area = length * width; cout << "长为 "<< length << " 宽为 " << width << " 的矩形的面积是 " << area << endl; } int main() { rectangleArea(10, 5); rectangleArea(3.5, 2.5); rectangleArea(9.7, 4.2); return 0; }
我们可以看到,cout在函数体内被调用,显示的结果和之前把cout放在main函数里是一样的。只不过我们用的方法不一样罢了。
菜单
我们来写一个餐馆菜单的例子。
#include <iostream> using namespace std; int menu() { int choice = 0; while (choice < 1 || choice > 4) { cout << "菜单 :" <<endl; cout << "1 : 北京烤鸭" <<endl; cout << "2 : 麻婆豆腐" <<endl; cout << "3 : 鱼香肉丝" <<endl; cout << "4 : 剁椒鱼头" <<endl; cout << "您的选择是 ? " <<endl; cin >> choice; } return choice; } int main() { switch (menu()) { case 1: cout << "您点了北京烤鸭" << endl; break; case 2: cout << "您点了麻婆豆腐" << endl; break; case 3: cout << "您点了鱼香肉丝" << endl; break; case 4: cout << "您点了剁椒鱼头" << endl; break; } return 0; }
这个程序还可以改进:你可以在用户输入一个错误的数字时显示一个错误信息,而不是直接继续让其点单。
总结
函数包含具有特定目的的一段代码。
每个C++程序至少有一个函数:main函数。这是程序的入口。
把程序切分为有特定作用的各个函数是管理代码的好方式。
程序中,我们可以多次调用同一个函数。
一个函数可以接收数据(通过参数),也可以返回数据(通过return)。
第一部分第八课预告
今天的课就到这里,一起加油吧!
下一课我们学习:传值引用,文件源头
本文出自 “程序员联盟 frogoscar” 博客,请务必保留此出处http://4526621.blog.51cto.com/4516621/1738449
以上是关于C++探索之旅第一部分第七课:函数效应,分而治之的主要内容,如果未能解决你的问题,请参考以下文章