函数
函数定义
定义形式:
返回类型 函数名(形式参数列表)//函数首部
{
函数体声明部分
函数体执行语句
}//函数体
1.函数名: 实现函数需要确定函数名,以便调用时使用。
2.形式参数列表: 形式参数列表是函数与调用者进行数据交换的途径,也可以没有形式参数
一般形式为:
类型1 参数名1,类型2 参数名2,类型3 参数名3······
int fun(int x,int y,double z)
{
return z>3.14159?x:y;
}
//没有形式参数
int fun()
{
return 3;
}
int fun(void)
{
return 4;
}
3.返回类型: 返回类型可以是除了数组以外的内置数据类型或自定义类型。如果函数体内没有return语句会随机返回一个与返回类型相同的随机值。可以没有返回类型,调用没有返回值的函数只能按语句形式调用函数,因为没有返回值就不能参与表达式运算。
int fun(int x,int y,double z)
{
return z>3.14159?x:y;
}
//没有返回类型
void fun()
{
cout<<"hello!"<<endl;
}
void fun(void)
{
cout<<"hi!"<<endl;
}
4.函数体: 函数体包含声明部分和执行部分,是一组能实现特定功能的语句序列集合。函数体称为函数实现简称是实现,函数头称为接口
//判断一个数是否为素数
#include <iostream>
using namespace std;
int IsPrime(int m)
{
int i,ret=1;
for(i=2;i<=m-1;i++)
{
if(m%i==0)
{
ret=0;
break;
}
}
return ret;//ret=1表示是素数,ret=0表示不是素数
}
int main()
{
int m;
cin>>m;
if(IsPrime(m))
{
cout<<"YES"<<endl;
}else
{
cout<<"NO"<<endl;
}
return 0;
}
调用函数之前必须要有函数声明,函数定义既是函数定义也是函数声明
函数声明与调用
- 函数声明(原型):提供了函数调用所必须的接口信息
形式:
- 返回类型 函数名(类型1 形参1,类型2 形参2,······)
- 返回类型 函数名(类型1 ,类型2 ,······)
-
函数调用:实参可以是常量、变量、表达式和函数调用,各实参之间用逗号隔开,实参的类型、次序、个数应与形参一致
-
函数可以嵌套调用,但是在调用之前必须有先声明
-
函数的递归调用:函数直接或间接调用自己称为递归调用,使用递归记得定义递归结束条件,否则就会进入死循环
形式:
函数名(实参列表)
方式:
1.函数表达式
z=max(x,y);
2.函数调用语句
max(x,y);
3.函数实参
m=max(max(x,y),z);
实参和形参的联系
形式参数:
-
函数定义中的形式参数列表,简称形参
-
函数定义时指定的形参,在未进行函数调用时,并不实际占用内存中的存储单元
-
只有发生函数调用时,形参才分配实际的内存单元,接受主调函数传来的数据
-
当函数调用结束时,形参占用的内存单元被自动释放
-
形参只能是变量
实际参数:
-
函数调用时提供给被调函数的参数称为实际参数,简称实参
-
实参必须有确定的值,因为调用函数会将他们传递给形参。实参可以是常量、变量或表达式,还可以是函数的返回值
-
实参的类型、次序和数目要与形参一致
内联函数
- 定义:为了提高函数效率,即在编译时将被调函数的代码直接嵌入到主调函数中,取消调用这个环节,这种嵌入到主调函数中的函数叫做内联函数
定义形式:
inline 返回类型 函数名(形式参数列表)
{
函数体
}
-
内联函数的声明是在函数定义的类型前加上inline修饰符
-
内联函数由简单语句构成,所以其中不允许使用循环语句和switch语句
-
内联函数的声明必须出现在内联函数第一次被调用之前
默认参数与函数重载
默认函数
- 定义:在函数定义或函数声明时,为形参指定默认值,这样的参数称为默认参数
定义形式:
返回类型 函数名(···,类型 默认参数名=默认值)
{
函数体
}
-
如果函数声明时设置了默认参数,那么不能在函数定义中再次设置(即声明和定义中只能存在一次默认参数设置),但是在类中的函数必须在类里面声明默认参数
-
可以设置多个默认参数,设置的顺序自右向左(某个参数有默认值的话它右边的所有参数都必须是默认参数)
int volume(int l=1,int w=1,int z=1)//正确
int volume(int l,int w=1,int z=1)//正确
int volume(int l,int w,int z=1)//正确
int volume(int l=1,int w,int z)//错误
int volume(int l,int w=1,int z)//错误
- 默认值可以是常量、全局变量,函数调用等(调用实参必须是常量或全局变量的表达式),默认值,函数实参不可以是局部变量
int p1=2,p2=10;
int max(int a,int b)
{
int c=1;
return a>b ? a : b;
}
int volume(int l,int w,int h=1);//正确,允许常量
int volume(int l,int w,int h=p1+p2);//正确,允许全局变量的表达式
int volume(int l,int w,int h=max(5,6));//正确,允许函数调用
int volume(int l,int w,int h=max(p1,p2));//正确,允许函数调用和全局变量
int volume(int l,int w,int h=c);//错误,不能使用局部变量
- 默认参数函数的调用 本质上是编译器根据函数声明或函数定义时默认参数设置,对函数调用中没有给出来的实参自动用默认值表达式"补齐"再进行编译
#include <iostream>
using namespace std;
int p1=2,p2=10;
int max(int a,int b)
{
return a>b ? a :b;
}
int volume(int l=1,int w=p1+p2,int h=max(p1,p2))
{
return l*w*h;
}
int main()
{
cout<<"v0="<<volume()<<endl;
cout<<"v1="<<volume(5)<<endl;
cout<<"v2="<<volume(5,10)<<endl;
cout<<"v3="<<volume(5,10,15)<<endl;
}
函数重载
- 定义:函数重载是在同一个域中用同一个函数名来定义多个函数,但参数列表应有所不同,可以是参数个数不同,也可以是参数类型不同,或者两者都不同
#include <iostream>
using namespace std;
int max(int a,int b)
{
return a>b ? a : b;
}//整型版本
double max(double a,double b)
{
return a>b ? a : b;
}//双精度版本
long max(long a,long b)
{
return a>b ? a : b;
}//长整型版本
int main()
{
int i=12,j=-12,k;
k=max(i,j);//调用整形版本max
cout<<"int max="<<k<<endl;
double x=123.4,y=65.43,z;
z=max(x,y);//调用双精度形版本max
cout<<"double max="<<z<<endl;
long a=7654321,b=1234567,c;
c=max(a,b);//调用长整形版本max
cout<<"long max="<<c<<endl;
}
-
重载函数的形参必须不同
-
编译器根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数
-
重载函数用于函数功能相同但参数不同的时候,不要将不同功能函数声明为重载函数,否则容易出错
函数模板与库函数调用
- 定义:函数模板是一个独立于类型的函数,可作为一种模式,产生函数的特定类型版本
template <模板形参表> 返回类型 函数名(形参列表)
{
函数体
}
template <typename T> T abs(T x)
{
return x<0 ? -x : x;
}
int main()
{
int m=-5;
double n=-5.5;
cout<<abs(m)<<","<<abs(n)<<endl;
}
-
使用函数模板可以设计通用型的函数,这些函数与类型无关并且只在需要时自动实例化,形成"批量型"的编程方式
-
模板形参表:用一对尖括号"<>"括起来的一个或多个模板形参列表,不允许为空,形参之间以逗号","分割,有以下两种形式:
- typename 参数类型1,typename 参数类型2,······
- class 参数类型1,class 参数类型2,······
-
调用库函数:
- 在程序中添加库函数声明
- 将库函数的目标代码连接到程序中