写在前面:大家好!我是【AI 菌】,一枚爱弹吉他的程序员。我
热爱AI、热爱分享、热爱开源
! 这博客是我对学习的一点总结与记录。如果您也对
深度学习、机器视觉、算法、Python、C++
感兴趣,可以关注我的动态,我们一起学习,一起进步~
我的博客地址为:
【AI 菌】的博客
上一篇:
【C++养成计划】控制程序流程——判断与循环(Day5)
昨天,我们学习了C++程序中的两大控制流程:判断和循环。今天,我们来学习编程语言中
一个很重要的知识板块:函数
。
1. 初识函数
一说到函数,对于编程小白,可能首先联想到的是数学中的函数公式:
y
=
f
(
x
)
y
=
f
(
x
)
。其实呢?C++函数与数学函数式子是有一些相通之处,比如,它们一般都有着输入和输出;函数式中的映射关系,对应到C++函数中就是一种逻辑关系。
不同的是,
在C++中,函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 main() ,并且程序从主函数处开始执行
。具体可参见:
【C++养成计划】基本语法(Day2)
。
(1) 为何需要函数
其实,对于小型的应用程序来说,完全可以使用main()实现所有功能。
但是当程序越来越大,越来越复杂时,若想要main()中的代码依然保持简洁、逻辑清晰易读,就必须使用函数了
。
函数能够很好地划分和组织程序的执行逻辑。通过使用函数,可以将原本复杂冗长的程序划分为依次调用的程序块。
(2) 函数定义
在C++ 中,函数定义的一般形式如下:
return_type function_name(parameter list)
{
函数主体
}
由此可知,函数主要有如下4个组成部分:
返回类型 return_type
。是指函数返回值的数据类型,一个函数可以返回一个值。有些函数只执行某些操作不返回值,那么返回类型要设置为
viod
。
函数名称 function_name
。就是函数的名字,由我们自己设定,在调用函数时用到。
参数列表 parameter list
。参数就像是占位符。当函数被调用时,你向参数传递一个值,这个值被称为实际参数。
参数列表
包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数也可以不包含参数。
函数主体
。是函数的主体结构,由执行一个任务的若干语句构成。
下面举一个简单的例子,用函数实现:计算圆形的面积
#include <iostream>
using namespace std;
const double Pi = 3.14 ;
double Area_circle ( double r)
{
return Pi* r* r;
}
int main ( )
{
cout<< "请输入圆形的半径radius:" ;
double radius= 0 ;
cin>> radius;
cout<< "该圆的面积是:" << Area_circle ( radius) << endl;
return 0 ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
运行结果如下:
(3) 函数声明
函数声明会告诉编译器函数名称及如何调用函数。函数声明包括以下几个部分:
return_type function_name(parameter list);
很容易看出,
函数的声明和上面函数定义中的函数头一致,不同的是,句末要加上一个分号
。因此,针对上面计算圆形的面积的例子,Area_circle()函数声明形式如下:
double Area_circle ( double r) ;
在函数声明中,
参数的名称并不重要,只有参数的类型是必需的
,因此下面也是有效的声明:
double Area_circle ( double ) ;
函数声明最常用的两种情形:
若函数实现在mian()函数之后,当main()中需要调用该函数时,我们需要程序中main()前的位置提前声明该函数
。我们还是以计算圆形的面积为例:
#include <iostream>
using namespace std;
const double Pi = 3.14 ;
double Area_circle ( double r) ;
int main ( )
{
cout<< "请输入圆形的半径radius:" ;
double radius= 0 ;
cin>> radius;
cout<< "该圆的面积是:" << Area_circle ( radius) << endl;
return 0 ;
}
double Area_circle ( double r)
{
return Pi* r* r;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
当你在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的
。在这种情况下,你应该在调用函数的文件顶部声明函数。
(4) 函数调用
创建 C++ 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储该函数返回的值
。我们还是以计算圆形的面积为例:
#include <iostream>
using namespace std;
const double Pi = 3.14 ;
double Area_circle ( double r) ;
int main ( )
{
cout<< "请输入圆形的半径radius:" ;
double radius= 0 , area= 0 ;
cin>> radius;
area= Area_circle ( radius) ;
cout<< "该圆的面积是:" << area<< endl;
return 0 ;
}
double Area_circle ( double r)
{
double S= Pi* r* r;
return S;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
运行结果:
(5) 形参与实参
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁
。
比如,前面讲到的
函数定义和函数声明中的参数列表中的变量就是形参
。
当调用函数时,我们需要用到实参
。在调用函数的过程中,编译器会自动将实参传递给形参,然后执行函数体。
2. 带默认值的参数
在前面计算圆形的面积是例子中,我们将Pi声明为常量,因此后面就不能对其进行修改了。那么,当我们希望得到更高或更低的精度时,就不能为力了。
为了解决这种问题,我们可以给函数Area_circle()新增一个表示Pi的参数,并将其设置为默认值
。比如:
double Area_circle ( double r, double Pi= 3.14 ) ;
注意,第二个参数Pi的默认值是3.14。
对调用者来说,这个参数是可选的
,因此仍可使用下面的语句来调用Area_circle():
Area_circle ( radius) ;
如果,我们想得到更高的精度。在调用函数时,可以提供Pi的值,指定要实际要用的Pi值。指定的Pi值会覆盖默认值。比如:
Area_circle ( radius, 3.1416 ) ;
下面,仍以计算圆形的面积为例,演示如何编写包含默认值的函数。
#include <iostream>
using namespace std;
double Area_circle ( double r, double Pi= 3.14 ) ;
int main ( )
{
cout<< "请输入圆形的半径radius:" ;
double radius= 0 , area= 0 ;
cin>> radius;
area= Area_circle ( radius) ;
cout<< "使用默认值Pi,该圆的面积是:" << area<< endl;
area= Area_circle ( radius, 3.1416 ) ;
cout<< "指定Pi=3.1416后,该圆的面积是:" << area<< endl;
return 0 ;
}
double Area_circle ( double r, double Pi)
{
double S= Pi* r* r;
return S;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
运行结果:
3. 递归函数
在有些情况下,可让函数调用它自己,这样的函数称为递归函数
。递归函数必须有明确的退出条件,满足这种条件后,函数将返回,而不再调用自己。
在计算斐波那契数列时,递归函数很有用。
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
使用递归函数实现如下:
#include <iostream>
using namespace std;
int Fibonacci ( int n)
{
if ( n== 1 || n== 2 )
return 1 ;
else
return Fibonacci ( n- 1 ) + Fibonacci ( n- 2 ) ;
}
int main ( )
{
int n= 0 ;
cin>> n;
cout<< Fibonacci ( n) ;
return 0 ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
4. 使用函数处理不同类型的数据
并不是每次只能给函数传递一个值,还可以将数组等传递给函数。这样可在函数中操纵更多的数据和参数。
(1) 函数重载
名称和返回类型相同,但是参数不同的函数被称为重载函数
。
在程序中,如果需要使用不同的参数调用具有特定名称和返回类型的函数,重载函数将很实用。
下面举个例子,计算圆和圆柱的面积。计算圆面积的函数需要一个参数——半径r,而计算圆柱面积的函数还需要一个参数——高度h。这两个函数需要返回的数据类型相同,都是面积。在C++中,我们可以定义两个重载的函数,它们都叫Area,返回类型都是double,但第一个函数仅接受r为参数,第二个接受r、h作为参数。
#include <iostream>
using namespace std;
const double Pi= 3.14 ;
double Area ( double r) ;
double Area ( double r, double h) ;
int main ( )
{
int r= 0 , h= 0 ;
cout<< "输入圆柱体的半径r和高h:" ;
cin>> r>> h;
cout<< "圆的面积是:" << Area ( r) << endl;
cout<< "圆柱的表面积是:" << Area ( r, h) ;
return 0 ;
}
double Area ( double r)
{
return Pi* r* r;
}
double Area ( double r, double h)
{
return 2 * Area ( r) + 2 * Pi* r* h;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
运行结果:
(2) 将数组传递给函数
显示一个数组的函数类似于下面这样:
void ShowArr ( int NumArr[ ] , int length) ;
下面,举例显示整型数组和字符数组中的每个元素:
#include <iostream>
using namespace std;
void ShowArr ( int NumArr[ ] , int length)
{
for ( int i= 0 ; i< length; i++ )
cout<< NumArr[ i] << " " ;
}
void ShowArr ( char CharArr[ ] , int length)
{
for ( int i= 0 ; i< length; i++ )
cout<< CharArr[ i] << " " ;
}
int main ( )
{
int Numbers[ 5 ] = { 0 , 1 , 2 , 3 , 4 } ;
ShowArr ( Numbers, 5 ) ;
cout<< endl;
char Characters[ 6 ] = { 'H' , 'E' , 'L' , 'L' , 'O' , '\0' } ;
ShowArr ( Characters, 6 ) ;
return 0 ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
运行结果:
(3) 按引用传递参数
有时候,你希望函数修改的变量能在其外部也可用,为此,可将形参的类型声明为引用
,下面以Area()函数计算面积为例,以参数的方式按引用返回它:
void Area ( double r, double & result)
{
result= Pi* r* r;
}
其中符号&,它告诉编译器,不要将第二个实参复制给函数,而将指向该实参的引用传递给函数
。
因此,该函数的返回类型是void,因为该函数不再通过返回值提供计算得到的面积,而是按引用以输出参数的方式提供它。
下面显示如何按引用返回圆的面积:
#include <iostream>
using namespace std;
const double Pi= 3.14 ;
void Area ( double r, double & result)
{
result= Pi* r* r;
}
int main ( )
{
cout<< "输入半径radius:" ;
double radius= 0 ;
cin>> radius;
double GetResult= 0 ;
Area ( radius, GetResult) ;
cout<< "圆的面积是:" << GetResult<< endl;
return 0 ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
运行结果: