一、函数定义
<1>函数定义的语法形式
类型标识符 函数名(形式参数表)/形参表<type1>name1,<type2>name2,…是被初始化的内部变量,寿命和可见性仅限于函数内部 类型标识符即int double float/
{
语句序列
}//类型标识符表示返回值的类型,由return语句给出返回值;若无返回值,写void不写return
二、函数调用
<1>调用函数需要先声明函数原型
若函数定义在调用点之前,可以不另外声明;
若函数定义在调用点之后,必须要在调用函数前声明函数原型:
函数原型:类型标识符 被调用函数名(含类型说明的形参表)
<2>函数调用形式
函数名(实参列表)
<3>嵌套调用
嵌套调用:在一个函数的函数体中,调用另一函数。
<4>递归调用
函数直接或间接调用其本身
<5>例3-1编写一个求x的n次方的函数
#include <iostream>
using namespace std;
//计算5的2次方
double power(double x, int n) {//定义函数,函数名power,有两个形参x和n
double val = 1.0;
while (n--) {val *= x;//n先减一,val再乘以x一次,到n=0执行一次后退出.
}
return val;
}
int main() {
cout << "5 to the power 2 is "
<< power(5, 2) << endl;//x=5,n=2
return 0;
}
<6>例3-2 数制转换
输入一个8位二进制数,将其转换为十进制数输出。
例如:从键盘输入1101
1101=1×23+1×22+0×21+1×20=13
所以,程序应输出13
源代码:
#include <iostream>
using namespace std;
double power (double x, int n); //计算x的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;
}
<7>void语句
void 的作用
1.对函数返回的限定,这种情况我们比较常见。
2.对函数参数的限定,这种情况也是比较常见的。
一般我们常见的就是这两种情况:
当函数不需要返回值值时,必须使用void限定,这就是我们所说的第一种情况。例如:void func(int a,char *b)。
当函数不允许接受参数时,必须使用void限定,这就是我们所说的第二种情况。例如:int func(void)。
三、嵌套与递归
<1>嵌套
<2>递归——递推和回归
例3-8 求n!
源代码:#include <iostream>
using namespace std;
unsigned fac(int n){
unsigned f;
if (n == 0)
f = 1;
else
f = fac(n - 1) * n;
return f;
}
int main() {
unsigned n;
cout << "Enter a positive integer:";
cin >> n;
unsigned y = fac(n);
cout << n << "! = " << y << endl;
return 0;
}
运行结果:
Enter a positive integer:8
8! = 40320
四、参数传递
在函数被调用时才分配形参的存储单元
实参可以是常量、变量或表达式
实参类型必须与形参相符
值传递是传递参数值,即单向传递
引用传递可以实现双向传递
常引用作参数可以保障实参数据的安全
例3-11值传递-输入两个整数并交换
#include<iostream>
Using namespace std;
Void swap(int&a,int&b){ //void语句不规定函数类型,用”&字母“表示其作为一个东西的别名,即”引用“
int t=a;//交换值需要中间变量,此处定义t,称为局部变量,把a的值暂存于t
a=b;
b=t;
}
Int main(){
int x=5,y=10;
cout<<"x="<<x<<"y="<<y<<endl;
swap(x,y);//使a成为x的引用,b成为y的引用,引用就可以换值,而没有&,只是a和b换值,其实x,y并未换值
cout<<"x="<<x<<"y="<<y<<endl;
return 0;
}
五、引用类型
&是标识符,如
Int i,j;
Int &ri=I;//定义int引用ri,初始化为i的引用,注意C++中定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象
j=10;
Ri=j;//相当于i=j
一旦一个引用被初始化后,就不能改为指向其它对象。
引用可以作为形参(即上面的例题,是其主要用途)
*六、含有可变参数的函数(可变数量形参,可先跳过,学完第九章再学)
1.++标准中提供了两种主要的方法
如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型;
如果实参的类型不同,我们可以编写可变参数的模板(第9章)。
2.initializer_list
initializer_list是一种标准库类型,用于表示某种特定类型的值的数组,该类型定义在同名的头文件中。
<1>initializer_list提供的操作
<2>initializer_list的使用方法
initializer_list是一个类模板(第9章详细介绍模板)
使用模板时,我们需要在模板名字后面跟一对尖括号,括号内给出类型参数。例如:
initializer_list<string> ls; // initializer_list的元素类型是string
initializer_list<int> li; // initializer_list的元素类型是int
initializer_list比较特殊的一点是,其对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。
含有initializer_list形参的函数也可以同时拥有其他形参
<3>initializer_list使用举例
在编写代码输出程序产生的错误信息时,最好统一用一个函数实现该功能,使得对所有错误的处理能够整齐划一。然而错误信息的种类不同,调用错误信息输出函数时传递的参数也会各不相同。
使用initializer_list编写一个错误信息输出函数,使其可以作用于可变数量的形参
Void log_info(initializer_list<string> 1st){
for(auto &info:1st)//for语句遍历1st,auto自动推断元素为string类型
cout<<info<<' ';
count<<endl;
}
Log_info({"Hello","World","!"});//调用参数
七、内联函数(常用于实现简单功能的函数)
声明时使用关键字 inline。
编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销。
注意:
内联函数体内不能有循环语句和switch语句;
内联函数的定义必须出现在内联函数第一次被调用之前;
对内联函数不能进行异常接口声明。(第12章的内容)
例3-14 内联函数应用举例
#include <iostream>
using namespace std;
const double PI = 3.14159265358979;
inline double calArea(double radius) {//内联函数,作用为计算圆面积
return PI * radius * radius;
}
int main() {
double r = 3.0;
double area = calArea(r);
cout << area << endl;
return 0;
}
八、constexper函数
constexpr函数语法规定
constexpr修饰的函数在其所有参数都是constexpr时,一定返回constexpr;
函数体中必须有且仅有一条return语句。
constexpr函数举例
constexpr int get_size() { return 20; }
constexpr int foo = get_size(); //正确:foo是一个常量表达式
九、带默认参数值的函数
1.可以预先设置默认的参数值,如果调用时给出实参,则采用实参值,否则采用预先设置的默认参数值。
例如:Int add(int x=5,int y=6){//加法函数,如果实参没有给值,则默认x=5,y=6
Return x+y;
}
Int main(){
add(10,20);//结果为10+20
add(10);//结果为10+6
add();//结果为5+6
}
2.默认参数的说明次序
<1>有默认参数的形参必须列在形参列表的最右边
<2>调用时实参与形参的结合次序是从左到右
例如:
Int add(int x,int y=5,int z=6);//正确
Int add(int x=1,int y=5,int z);//错误
Int add(int x,=1int y,int z=6);//错误
3.默认参数值与函数的调用位置
如果一个函数有原型声明,且原型声明在定义之前,则默认参数值应在函数原型声明中给出;如果只有函数的定义,或函数定义在前,则默认参数值可以函数定义中给出。
例如:
十、函数重载
C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。
例:
注意事项
重载函数的形参必须不同:个数不同或类型不同。
编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:
例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
十一、系统函数调用
1.C++的系统库中提供了几百个函数可供程序员使用,例如:
求平方根函数(sqrt)
求绝对值函数(abs)
2.使用系统函数时要包含相应的头文件,例如:
<cmath>
<math>
例3-17 系统函数应用举例
题目:
从键盘输入一个角度值,求出该角度的正弦值、余弦值和正切值。
分析:
系统函数中提供了求正弦值、余弦值和正切值的函数:sin()、cos()、tan(),函数的说明在头文件cmath中。
源代码
#include <iostream>
#include <cmath>
using namespace std;
const double PI = 3.14159265358979;
int main() {
double angle;
cout << "Please enter an angle: ";
cin >> angle; //输入角度值
double radian = angle * PI / 180; //转为弧度
cout << "sin(" << angle << ") = " << sin(radian) <<endl;
cout << "cos(" << angle << ") = " << cos(radian) <<endl;
cout << "tan(" << angle << ") = " << tan(radian) <<endl;
return 0;
}
运行结果
30
sin(30)=0.5
cos(30)=0.866025
tan(30)=0.57735