写在前面:大家好!我是【AI 菌】,一枚爱弹吉他的程序员。我
热爱AI、热爱分享、热爱开源
! 这博客是我对学习的一点总结与记录。如果您也对深度学习、机器视觉、算法、Python、C++
感兴趣,可以关注我的动态,我们一起学习,一起进步~
我的博客地址为:【AI 菌】的博客
上一篇:【C++养成计划】控制程序流程——判断与循环(Day5)
昨天,我们学习了C++程序中的两大控制流程:判断和循环。今天,我们来学习编程语言中一个很重要的知识板块:函数。
文章目录
- 1. 初识函数
- (1) 为何需要函数
- (2) 函数定义
- (3) 函数声明
- (4) 函数调用
- (5) 形参与实参
- 2. 带默认值的参数
- 3. 递归函数
- 4. 使用函数处理不同类型的数据
- (1) 函数重载
- (2) 将数组传递给函数
- (3) 按引用传递参数
1. 初识函数
一说到函数,对于编程小白,可能首先联想到的是数学中的函数公式: y = f ( x ) 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;
//定义Area_circle函数,实现对圆求面积
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;
}
运行结果如下:
(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; //返回圆的面积
}
- 当你在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,你应该在调用函数的文件顶部声明函数。
(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); //将函数的返回值给area
cout<<"该圆的面积是:"<<area<<endl;
return 0;
}
double Area_circle(double r)
{
double S=Pi*r*r; //就算圆的面积
return S; //返回面积S
}
运行结果:
(5) 形参与实参
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
比如,前面讲到的函数定义和函数声明中的参数列表中的变量就是形参。
当调用函数时,我们需要用到实参。在调用函数的过程中,编译器会自动将实参传递给形参,然后执行函数体。
2. 带默认值的参数
在前面计算圆形的面积是例子中,我们将Pi声明为常量,因此后面就不能对其进行修改了。那么,当我们希望得到更高或更低的精度时,就不能为力了。为了解决这种问题,我们可以给函数Area_circle()新增一个表示Pi的参数,并将其设置为默认值。比如:
double Area_circle(double r, double Pi=3.14);
注意,第二个参数Pi的默认值是3.14。对调用者来说,这个参数是可选的,因此仍可使用下面的语句来调用Area_circle():
Area_circle(radius); //这里省略了第二个参数,因此将使用默认值Pi=3.14
如果,我们想得到更高的精度。在调用函数时,可以提供Pi的值,指定要实际要用的Pi值。指定的Pi值会覆盖默认值。比如:
Area_circle(radius, 3.1416); //指定Pi=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); //将函数的返回值给area
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; //返回面积S
}
运行结果:
3. 递归函数
在有些情况下,可让函数调用它自己,这样的函数称为递归函数。递归函数必须有明确的退出条件,满足这种条件后,函数将返回,而不再调用自己。
在计算斐波那契数列时,递归函数很有用。
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
使用递归函数实现如下:
#include <iostream>
using namespace std;
int Fibonacci(int n) //Fibonacci数列函数
{
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); //输出Fibonacci数列第n个数
return 0;
}
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;
}
运行结果:
(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;
}
运行结果:
(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;
}
运行结果: