3.1 函数的定义与使用
一个C++程序可以由一个主函数和若干子函数构成。主函数是程序执行的开始点。由主函数调用子函数,子函数可以再调用其他子函数。
调用其他函数的函数称为主调函数,被其他函数调用的函数称为被调函数。
1.1 函数的定义
函数定义的语法形式:
类型说明符 函数名(含类型说明的形式参数表)
{
语句序列
}
形式参数表的内容如下:
type1 name1,type2 name2,....typen name n
type1 type2,...typen 是类型标识符表示形参的类型。name1,name2,....namen是形参名。
形参的作用:实现主调函数与被调函数之间的联系。通常将函数所处理的数据、影响函数功能的因素或者函数处理额结果作为形参。
如果一个函数的形参表为空,则表示它没有任何形参。main函数形参称为命令行参数,由操作系统在启动程序时初始化。
函数的返回值和返回值类型:
函数可以有一个返回值,函数的返回值是需要返回给主调函数的处理结果。类型说明符规定函数返回值的类型,函数的返回值由return 语句给出,格式如下:
return 表达式;
除了指定函数的返回值外,return语句还有一个作用: 结束当前函数的执行。
例如:main函数的返回值最终传递给操作系统。
一个函数也可以不将若任何值返回给主调函数,这时它的类型标识符为void,可以不写return语句,但可以写一个不带表达式的return语句,用于结束当前函数的调用,格式return;
1.2 函数的调用
函数在调用之前需要声明。函数的定义就属于函数的声明,因此,在定义了一个函数之后就可以直接调用函数。但如果希望在定义一个函数前调用它,则需要在调用函数之前添加该函数的函数原型声明,函数原型声明的形式如下:
类型说明符 函数名(含类型说明的形参表);
如果在所有函数之前声明了函数原型,那么该函数原型在本程序文件中的任何地方都有效,也就是说在本程序文件中任何地方都可以依照原型调用相应的函数。如果是在某个主调函数内部声明了被调函数原型,那么该原型就只能在这个函数内部有效。
声明了函数原型之后,便可以按如下形式调用子函数:
函数名(实参列表)
实参列表应给出与函数原型形参个数相同、类型相符的实参,每个实参都是一个表达式。
例3-1 求x的n次方的函数
#include<iostream>
using namespace std;
//计算 x的n次方
double power(double x,int n){
double val = 1.0;
while(n--){
val *= x;
}
return val;
}
int main(){
cout<<"5 to the power 2 is "<<power(5,2) <<endl;
//函数调用作为 一个表达式出现在输出语句中
return 0;
}
程序中由于函数power的定义位于调用之前,所以无需对函数原型加以声明。
例3-2 输入一个八进制位数,将其转换为十进制数输出。
#include<iostream>
using namespace std;
//计算 x的n次方
double power(double x,int n);
int main(){
int value = 0;
cout<<"enter an 8 bit binary number:";
for(int i=7;i>=0;i--){
char ch;
cin>>ch;
if(ch=='1'){
value+=static_cast<int>(power(2,i));
}
}
cout<<"Decimal value is "<<value<<endl;
return 0;
}
double power(double x,int n){
double val = 1.0;
while(n--){
val *= x;
}
return val;
}
程序中由于power函数的定义位于它的调用之后,因此要事先声明power函数原型。
函数允许嵌套调用,递归调用。
1.3 函数的参数传递
在函数未被调用时,函数的形参并不占用实际的内存空间,也没有实际的值。只有在函数被调用时才为形参分配存储单元,并将实参与形参相结合,每一个实参都是一个表达式,其类型必须与形参相符。函数的参数传递指的是形参与实参结合的过程,结合的方式有值传递和引用传递。
1 值传递
值传递是指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参(直接将实参的值传递给形参)。一旦形参获得值便与实参脱离关系,此后无论形参发生了怎样的改变都不会影响到实参。
例3-11 将两个整数交换次序后输出
#include<iostream>
using namespace std;
void swap(int a,int b){ //值传递
int t =a;
a = b;
b = t;
}
int main(){
int x=5,y=10;
cout<<"x="<<x<<" y="<<y<<endl;
swap(x,y);
cout<<"x="<<x<<" y="<<y<<endl;
return 0;
}
运行结果:
x=5 y=10
x=5 y=10
2 引用传递
引用是一种特殊类型的变量,可以认为是另一变量的别名。
int i,j;
int &ri =i; //建立一个int型的引用ri,并将其初始化为变量i的一个别名
j = 10;
ri =j; //相当于i=j;
使用引用必须注意下列问题:
1 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。
2一旦一个引用被初始化后,就不能改为指向其他对象。
也就是说一个引用从诞生起就必须确定是哪个变量的别名,而且始终只能作为这一变量的别名,不能另作它用。
用引用作为形参,在函数调用时发生的参数传递称为引用传递。
例3-12 引用传递 交换两个整数
#include<iostream>
using namespace std;
void swap(int &a,int &b){ //引用传递
int t =a;
a = b;
b = t;
}
int main(){
int x=5,y=10;
cout<<"x="<<x<<" y="<<y<<endl;
swap(x,y);
cout<<"x="<<x<<" y="<<y<<endl;
return 0;
运行结果:
x=5 y=10
x=10 y=5
3.2 函数重载
在编程时,可以对不同功能赋予相同的函数名,编译时会根据上下文(实参的类型和个数)来确定使用哪一具体功能。
两个以上的函数,具有相同的函数名,但形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数。
注意:重载函数的形参必须不同:个数不同或形参类型不同。编译程序对实参和形参的类型及个数进行最佳匹配来选择调用哪一个函数。如果函数名相同,形参类型也相同,无论函数返回值类型是否相同,在编译时会被认为是语法错误(函数重复定义)。
例3-16 重载函数举例
编写两个sumOfSquare的重载喊函数,分别求两个整数的平方和及两实数平方和
#include<iostream>
using namespace std;
int sumOfSquare(int a,int b) //函数重载实例
{
return a*a+b*b;
}
double sumOfSquare(double a, double b)
{
return a*a+b*b;
}
int main(){
int m,n;
cout<<"enter two integer:";
cin>>m>>n;
cout<<"their sum of square: "<<sumOfSquare(m,n)<<endl;
double x,y;
cout<<"enter two real number:";
cin>>x>>y;
cout<<"their sum of square: "<<sumOfSquare(x,y)<<endl;
return 0;
运行结果:
enter two integer:3 5
their sum of square: 34
enter two real number:2.3 5.8
their sum of square: 38.93