函数利用

一个程序即由一个main函数和若干其他用户自定义函数(完成特定功能的程序模块)组成;

通过定义函数创建可被重复使用的代码以简化程序

分类:库函数(系统提供)+自定义函数(用户按需定义)

定义函数的一般形式

1)无参函数版([]表示可省略)

执行时无需从主调函数调用数据进来

1
2
3
4
5
6
/*这都是例子哈哈哈哈哈*/
int Luxsie([void]) //如果主调函数不需要这个函数返回值,则直接写成void Luxsie()【不带return语句】
{
int x=727; //声明部分
cout<<x<<endl; //执行部分
}

2)有参数版

执行时需接收来自主调函数传来的数据,实参与形参的类型必须相同或者是相容的;

相容的意思就是float b可以直接转成int x,然后b顺利送到形参x;

字符型与整型可以互相通用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
实参:须有确定值,以能有东西赋给形参
形参: 定义时必须在首部的括号内指明类型
实参与形参的传递是单向的,调用时给形参分配存储单元是不同于实参的且是临时的(结束后会被释放)
*/
int max(inx,int y){ //函数值为整型,定义两个会传过来的形参,形参就是被调用函数括号内的变量名
int z; //声明部分
z = x>y ?x:y; //三目运算符,将大值赋给z
return (z) //将z的值作为函数值返回调用点
}

int main(){
int a,b,c;
a=20; //它俩是实参,有具体的数值,主函数内的
b=10;
c=max(a,b); //z的值会返回到这里作为c的结果
cout<<c;
return 0;
}

3)返回值的说明

一但执行return语句,则函数后面的语句都不再执行;

一个函数中可以有一个以上的return语句,执行到哪一个,哪一个起作用;

1
2
3
4
5
6
int  max( int x , int y ) 
{ if( x > y )
return x ;
else
return y ; //如果返回值的类型和函数定义的不一致,则根据函数类型返回
}

函数的调用

主调函数:主动调用其他函数

函数的调用:主调对被调的调用

调用函数的形式:函数名([实参表列,用逗号分隔])

实参表列可省略不写,一般是那种无需传参的;

若被调函数位置在主调函数的下面,则在调用前先写一遍声明部分(也是就是函数首部,放在其他函数外面),要不不能正常编译,声明时不需要形参名和函数体,但要告知形参的个数和类型;

int max(int,int);,所以一般都写在前面,使结构更简单

1)调用方式

  • 函数语句

不要求函数带回值,单独作为一个语句,如Luxsie();

  • 函数表达式

出现在表达式中,要求带回一个确定值以参与运算,如c=2+max(a,b);

  • 函数参数

函数调用作为另一个函数调用的实参,被调用函数必须存在,若调的main函数则要在程序开头引用,如#include<cmath>

嵌套调用

[!WARNING]

C++中不允许在一个函数中对另一个函数做完整定义,程序中的每一个定义平行而独立;

但可以在调用一个函数的过程中再去调用另一个(比如main调用f1,然后f1里调用一个f2)

递归调用

在调用一个函数的过程中又直接/间接的调用该函数本身,要格外注意什么时候调用结束【一般使用if语句来终止,包含此形式的成为递归函数】

1
2
3
4
5
6
7
8
9
10
11
12
13
int age(int); //函数声明
int main() //主函数
{
cout<<age(5)<<endl;
return 0;
}

int age(int x){ //定义求年龄的递归函数
int z;
if(n==1) c=10;
else c = age(n-1)+2;
return(c);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*例:用递归求n!*/
#include <iostream>
using namespace std;
long fac(int);
int main(){
int n;
long y;
cin>>n;
y=fac(n);
cout<<y;
return 0;
}
long fac(int a){
long f;
if(n<0){
cout<<"ERROR!"<<endl;
f = -1; //错了也要给一个值返回去
}
else if (a==0||a==1) f=1;
else f = fac(a-1)*a; //n>1时做递归调用
return f;
}

内置函数

同一函数被反复调用的话会在往返过程中消耗大量时空资源,增加调用开销,因此使用内置函数解决

在编译时直接将被调函数的代码嵌入到主调函数中(实参会对原代码中的形参做相应的位置替换),而不做流程的跳转,因此称为内置函数,形式为inline 数据类型 函数名(形参说明){}【一定要注明inline】

虽然节省了运行时间,但增加了目标程序长度,因此仅适用于使用频繁且规模很小的简单声明函数【不含复杂控制语句,如switch,循环,···】

函数重载

C++允许同一个函数名定义多个函数,而这些函数的参数个数和参数类型可以不同,旨在解决函数功能相同但参数类型不同的麻烦;

若只是返回值不同就不构成重载;

重载的形参必须个数不同或类型不同或顺序不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
int main()
{ int max(int a,int b,int c); //函数声明
double max(double a,double b,double c); //函数声明
long max(long a,long b,long c); //函数声明
int i1,i2,i3,i;
cin>>i1>>i2>>i3; //输入3个整数
i=max(i1,i2,i3); //求3个整数中的最大数
cout<<"i_max="<<i<<endl;
double d1,d2,d3,d;
cout<<"请输入3个实数:"<<endl;
cin>>d1>>d2>>d3; //输入3个双精度数
d=max(d1,d2,d3); //求3个双精度数中的最大数
cout<<"d_max="<<d<<endl;

return 0;

在使用时,同名函数的功能应该相同或相近,若完全不相关就很影响可读性

函数模板

C++提供函数模板(建立一个通用函数),其函数类型和形参不具体指定而用虚拟类型代表

定义函数模板的一般形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename T>
T 通用函数定义 //T:虚拟数据类型名,可由用户自定义,调用时可由任何实参类型取代

template <class T>
T 通用函数定义
/*下面是一个例子~~~*/
template<typename T> //模板声明,其中的 T为类型参数
T max(T a, T b, T c) //定义一个通用函数,用 T作虚拟的类型名
{
if(b>a) a=b;
if(c>a) a=c;
return a;
}
int main(){
cout<<"int_max=" << max(85,16,129) <<endl; //这样会直接用int替代T
}

主要是相较于函数重载,这样用程序更简洁方便,但只适用于函数体相同且函数参数个数相同仅参数类型不同的情况

有默认函数参数

为某个函数设置默认值,则在后续每次调用时避免重复赋值;

如果函数的定义在函数调用之后,需要在函数调用之前有函数声明;那么若在函数声明中给出默认值,则在函数定义时一般不给默认值(否则会报错:重复指定默认值)。

[!WARNING]

一旦某个参数指定了默认值,它右边所有的参数都必须也指定默认值

1
2
3
4
void f4(float a, int c, int b=0, char d='a');
···
//调用时,
f4(3.5, 5) //最后两个形参会取默认值

对于同一个函数不能既作为重载函数,又作为有默认参数的函数。

局部变量

作用域仅在所定义的函数或复合语句内,形参就局部变量,只能在函数内部使用;因此在不同函数中可以使用同名的变量以代表不同的对象,互不干扰。

1
2
3
4
5
6
7
int max( int a, int b) ;  //函数声明中出现形参a,b
……
int max (int x, int y ) //函数定义, 形参是x,y
{
cout<< x << y << endl; //合法, x, y在函数体中有效
cout<< a << b << endl; //非法, a, b在函数体中无效
} //编译时认为max函数体中的a和b未经定义。

全局变量

从定义开始到程序结束始终生效,为程序中所有函数所共用

在局部变量的作用范围内,局部变量优先于全局变量

其作用旨在增加函数间的数据联系

不过因其在整个执行过程中都要占用存储单元,而不是仅在需要时才开辟单元,因此非必要不使用全局变量,否则会导致通用性降低(函数执行时受到外部变量影响),且降低程序的清晰程度

相较于局部变量,全局变量有自己的默认初始值:数值型为0,字符型为’ ‘,布尔型为0

变量的区分

定义:需要建立存储空间,如int a,系统是根据变量的定义去分配存储空间的

声明:不需要建立存储空间,如’extern int a;’(也称外部变量)

1
2
3
4
5
6
7
int main( )
{
/*这是变量的声明。声明a是一个已定义的外部变量(表示整型变量a是在后面定义的,或是在外部程序中定义的)*/
extern int a;
......
}
int a; //这才是定义,定义a为整型外部变量(全局变量)

静态变量

static声明,存储在内存的静态区,具有默认初始值,从程序运行开始直至结束一直占据固定的存储单元

注:“static a;” 是不合法的,应写成 “static int a;”

使用方式:

  • 去声明局部变量:本函数调用结束后不释放,在程序执行整个期间始终存在,留作下次继续用,不再初始化恢复初值
  • 声明全局变量:则该变量的作用域仅在本文件中生效,对于那种其他文件的import调用就不管用了

其他变量还有寄存器变量(register),自动变量/动态变量(auto)

内部函数/静态函数

只能用于本文件,函数前用static去做标识

外部函数/动态函数

可跨文件使用,前加’extern’,不过一般省略不写,因为默认都是动态的

要调用其他文件里的函数的话,最好俩放同一项目文件中,并在使用前做好声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*这是个文件1,一会有用*/ 
int max( int x, int y )
{
int z;
z = x>y ? x : y ;
return z;
}



/*这是文件2,要去调用*/
int main(){
extern int max(int x,int y); //外来的,做个声明
int a,b;
cin>>a>>b;
cout<<max(a,b)<<endl;
return 0;
}

基于这样的思想,设计出了库函数,也就是cmath啥的这样只用#include <cmath>就可在该文件中合法使用各自数学库函数啦

头文件

就是刚才说的用#include指令包含的;是源文件中不可缺少的成分。

主要用于:

  • 对类型的声明(C++新增的,预定义的模板和类)

  • 对函数的声明#include

  • 对内置函数inline的定义

  • 宏定义(#define定义的符号常量;const声明的常变量)

  • 全局变量定义

  • 外部变量定义’extern int a;’

编程时,各函数包含在一个文件中,比如一个文件放主函数(调用其他的#include "T4-3.cpp"),两个文件放被调用的函数,这几个文件放同一个项目(.prj)里