C++教程(二):函数

+参考书: 郑莉(清华大学)C++ 语言程序设计 (第3版)

2 函数

较复杂的系统通常需要划分为若干个子系统分别独立的开发和调试。函数就是C/C++中子系统的一种体现。

调用其他函数的函数称为主调函数,被其他函数调用的函数称为被调函数。

2.1 函数的定义和使用

定义

类型标识符 函数名(形式参数表)
{
	语句序列
}

类型标识符规定了函数的类型,即返回值的类型,返回值需要使用return语句;无返回值的函数类型标识符为void,且不必写return语句。

形式参数表的通常形式为type1 name1, type2 name2,...,typen namen

调用

  • 调用之前需要在主调函数或所有函数之前,如下声明

    类型说明符 被调函数名(含类型说明的参数表)
    
  • 调用函数格式如下

    函数名(实参列表)
    

    实参列表应与函数原型对应。

    例子

    //2_1a.cpp
    #include <iostream>
    
    using namespace std;
    
    double power(double x, int n);
    
    int main()
    {
    	cout << " 5 to the power 2 is " << power(5,2) << endl;
    	return 0;
    }
    
    
    double power(double x, int n)
    {
    	double val = 1.0;
    	while (n--)
    		val *= x;
    	return(val);
    }
    

    编译运行结果

     5 to the power 2 is 25
    

2.2 函数调用的执行过程

对于操作系统而言,程序编译后生成可执行代码,存放在外部存储器中。程序启动时,系统将可执行代码装载到内存上并开辟一个进程,进程入口就是主函数。当需要调用其他函数时,系统暂停当前函数的执行,保存现场并保留下一条指令的地址,转到子函数入口执行子函数,子函数执行完毕,系统恢复主调函数现场并通过保存的地址找到下一条指令。

2.3 嵌套调用与递归调用

嵌套调用:被调函数还可以作为主调函数调用其他函数,例如

//2_3.cpp
#include <iostream>

using namespace std;

int main()
{
	int a,b;
	int fun1(int x, int y);
	cin >> a >> b;
	cout << "a, b的平方和: " << fun1(a, b) << endl;
}

int fun1(int x, int y)
{
	int fun2(int m);
	return (fun2(x)+fun2(y));
}

int fun2(int m)
{
	return (m*m);
}

编译运行结果

1
1
a, b的平方和: 2

递归调用:函数可以直接间接的调用自身,,典型的例子是求阶乘算法。

2.4 参数传递

值调用:发送函数调用时,给形参分配独立的内存空间;单向传递过程,一旦形参获得了值便与 实参脱离关系,此后形参的变化不会影响到实参。

引用调用:引用是一种特殊类型的变量,可以认为是变量的另一个别名。通过引用名与通过被引用的变量名访问变量的效果是一样的

int i,j;
int &ri = i;
j = 10;
ri = j;		//相当于 i = j;
  • 声明引用时,必须同时对它进行初始化,使它指向一个已经存在的对象;
  • 一旦一个引用被初始化后,就不能改为指向其他对象
// 2_4.cpp
#include <iostream>

using namespace std;

void Swap(int& a, int& b);

int main()
{
	int x(5), y(10);
	cout << "x=" << x << "    y=" << y << endl;
	Swap(x, y);
	cout << "x=" << x << "    y=" << y << endl;
	return 0;
}

void Swap(int& a, int& b)
{
	int t;
	t = a;
	a = b;
	b = t;
}

执行结果

x=5    y=10
x=10    y=5

2.5 内联函数

2.2节中讨论过,当调用函数时,进程需要保存现场和返回地址,返回主调函数还需要恢复现场;这一切都需要时间和空间方面的开销。对于功能简单,规模较小而又使用频繁的函数,这种额外的开销对于程序执行效率的影响很明显;于是设计了内联函数,并规定

  • 定义时使用关键字inline

    inline 类型说明符 被调函数名 (含类型说明的形参列表) {函数体语句;}
    
  • 内敛函数体内一般不能有循环语句和switch语句

  • 内联函数的定义必须在第一次调用之前

  • 对内联函数不能进行异常接口声明

  • 内联函数不能太过复杂,否则会被编译器转换为普通函数来处理;

主调函数调研内联函数时,并不像调用真正的函数那样;而是将内联函数的函数体直接复制到当前位置,于是就避免了保存现场的开销。

//2_5.cpp
#include <iostream>
using namespace std;
#define PI 3.14

inline double CalArea(double radius)
{
	return PI*radius*radius;
}

int main()
{
	double r(3.0);
	double area;
	area = CalArea(r);
	cout << area << endl;
}

执行结果

28.26

2.6 带默认形参值的函数

函数定义时可以带有默认的形式参数,调用函数时,若给出实参,则使用实参初始化形参;若没给出实参,则使用预先默认的形式参数。

  • 默认形参必须按从右向左的顺序声明,在有默认值的形参的右边,不能有无默认值的形参;

    int add(int a, int y = 5, int z = 6);		//正确
    int add(int a = 1, int y, int z = 6);		//错误
    int add(int a  = 5, int y = 6, int z);		//错误
    
  • 相同的作用域内,默认形参的说明应保持唯一;

  • 在不同的作用域,允许不同的默认形参说明;

  • 默认参数可能给函数重载带来麻烦;

默认参数例子

//2_6.cpp
#include <iostream>
#include <iomanip>

using namespace std;

int get_volume(int length, int width = 2, int height = 3);

int main()
{
	int x = 10, y = 12, z = 15;
	cout << "Some box data is " << endl;
	cout << get_volume(x,y,z) << endl;
	cout << get_volume(x,y) << endl;
	cout << get_volume(x) << endl;
	cout << get_volume(x,7) << endl;
	cout << get_volume(5,5,5) << endl;
	return 0;
}

int get_volume(int length, int width, int height)
{
	cout << setw(5) << length << setw(5) << width << setw(5) << height << ' ';
	return length*width*height;
}

执行

Some box data is 
   10   12   15 1800
   10   12    3 360
   10    2    3 60
   10    7    3 210
    5    5    5 125

2.7 函数重载

两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器会按照实参和形参的类型和个数的最佳匹配,自动调用一个函数,即函数重载。

  • 形参必须不同,个数或类型不同

    int add(int x, int y);			// 正确
    float add(float x, float y);	// 形参类型不同
    
    int add(int x, int y);			// 正确
    int add(int x, int y, int z);	// 形参数量不同
    
    int add(int x, int y);	// 错误
    int add(int a, int b);	// 编译器不以形参名区分函数
    
    int add(int x, int y);	// 错误
    void add(int x, int y);	// 编译器不以返回值区分函数
    
  • 不要将不同功能的函数定义为重载函数,避免对调用结果的误解、混淆;

2.8 C++ 系统函数

一些常用的函数,如sin()cos()sqrt等,非常通用;自己编写这些函数费时费力,代码质量不高,通用性也是问题,于是将这些常用函数汇集成一个个的C++库,包括函数库、类库等。

使用函数需要声明函数原型,这些原型在相应的头文件中,因此使用这些函数需要先通过include指令嵌入相应的头文件(函数声明)。以使用数学函数为例,需要嵌入头文件cmath

//2_8.cpp
#include <iostream>
#include <cmath>

using namespace std;

const double pi(3.14159265);

int main()
{
	double a,b;
	cin >> a;
	b = a*pi/180;
	cout << "sin(" << a << ") = " << sin(b) << endl;
	cout << "cos(" << a << ") = " << cos(b) << endl;
	cout << "tan(" << a << ") = " << tan(b) << endl;
	return 0;
}

执行

45
sin(45) = 0.707107
cos(45) = 0.707107
tan(45) = 1

利用系统函数可以大大减少编程的工作量,提高程序运行效率和可靠性;使用中需要注意

  • 了解函数库的内容和相应函数的声明、功能;
  • 了解函数声明在哪个头文件中;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值