C++学习第八弹:函数
在前面介绍C++的基础语法时,提到了每个C++都必须有一个主函数,实际上所有简单的程序都可以定义其他额外的函数。函数是一组一起执行一个任务的语句。我们可以把代码划分到不同的函数中,让每一个函数执行特定的任务。在使用函数时,需要对函数进行声明和定义,函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。 同时,C++标准库提供了大量的程序可以调用的内置函数可供直接调用。
定义一个函数:
C++ 中的函数定义的一般形式如下:
1 | return_type function_name( parameter list ) |
在 C++
中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
1.
return_type:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type
是关键字 void。 2.
function_name:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
3.
parameter list:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
4.
body of the function:函数主体,包含一组定义函数执行任务的语句,该函数的主要运行就在此处。
举个例子,下面我定义一个函数 max(),让他能比较并返回较大的一个数。
1 | // 函数返回两个数中较大的那个数 |
有时候我们需要调用其他文件中的函数,这时就需要对该函数进行声明才能使用。为什么主角释放技能前要大喊技能名称
?
函数声明:
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。 函数声明包括以下几个部分:
1 | return_type function_name( parameter list ); |
以上面的 max() 函数举例,如果我们想声明 max() 函数,那么就需要这样写:
1 | int max(int num1, int num2); |
当然,因为函数声明中参数的名称并不重要,可以省略,因此可以写成如下形式:
1 | int max(int, int); |
有时候我们可能会遇到一个文件中需要调用另一个文件中的函数,这时函数声明是必需的。在这种情况下,我们应该在调用函数的文件顶部声明函数。
讲完了如何定义并声明函数后,我们来看一下怎么调用刚刚的函数。
函数的调用:
创建 C++ 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。拿刚才的 max() 函数举例子:
1 |
|
下面说说调用函数时传递的所需参数。
函数参数:
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数,相应的还有一种叫实际参数的东西,我认为有必要在下面做一下详细说明。
实参&形参:
什么是形参?
形式参数就像函数内的其他局部变量,是在函数头括号内声明的,退出函数时被销毁。是某一函数私有的局部变量,。在函数外部中同名变量不会与之冲突。每次调用函数,会对函数头内定义的形参赋值。
什么是实参?
实际参数是主调函数赋给被调函数的具体值。它可以是常量,变量,正确的表达式,甚至是函数。但无论如何实参必须有一个具体的值以供拷贝于形参之中。
二者的关系?
简而言之,形参实际上是一种“空白”或是一种“占位符”,在函数调用的过程中,我们在某一已定义的函数中的括号内使用实参,此后函数将会拷贝实参至函数体内“填充”形参,并在函数体内得到使用。
讲完了形参和实参后,我们可以来说说调用函数时实参的传递过程了。
传值调用&引用调用:
实参的传递过程有两种不同的机制,其分别是传值调用和引用调用。
传值调用:
在传值调用过程中,形参是一个局部变量,其初值为调用函数是括号内赋予的实参的值。其只是使用了实参的值,在程序运行时,其在函数体内占用另外的内存空间,不对实参造成影响。比如我们定义一个函数 swap() 用来交换两个数据:
1 | // 函数定义 |
现在,让我们通过传递实际参数来调用函数 swap():
1 |
|
当上面的代码被编译和执行时,它会产生下列结果:
1 | 交换前,a 的值: 100 |
可以发现,虽然在函数内改变了 a 和 b 的值,但是实际上 a 和 b 的值没有发生变化。
引用调用:
在引用调用过程中,形参传递的不再只是一个值或是一个简单的结果,而是传递实参的地址。虽然形参仍然是一个占位符或是一个空白,但将实参拷贝到形参上后,它不再如传值调用一样占用额外的内存空间,而是和实参占用同一个内存空间。发生在形参上的任何改变都将与此同时体现在实参上。此时,你对形参的任何操作就相当于对实参在进行操作。此时声明函数 swap() 时就需要进行如下操作:
1 | // 函数定义 |
现在,让我们通过引用传值来调用函数 swap():
1 |
|
当上面的代码被编译和执行时,它会产生下列结果:
1 | 交换前,a 的值: 100 |
默认情况下,C++ 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的参数。之前提到的实例,调用 max() 函数时,使用了相同的方法。
参数的默认值:
定义一个函数时,我们可以为参数列表中后边的每一个参数指定默认值。当调用函数时,如果实际参数的值留空,则使用这个默认值。需要通过在函数定义中使用赋值运算符来为参数赋值。调用函数时,如果未传递参数的值,则会使用默认值,如果指定了值,则会忽略默认值,使用传递的值。我觉定还是引用一下菜鸟教程上的实例代码更加直观地展示一下使用方法:
1 |
|
当上面的代码被编译和执行时,它会产生下列结果:
1 | Total value is :300 |
小结:熟练掌握函数的用法可以让代码更加整洁,还可以避免重复造轮子,非常的重要。
