Prev: C++Ⅲ:数据类型,数组,指针
Next: C++Ⅴ:类与对象
1 函数介绍
1.1 函数(一)
一个[ruby=function]函数[/ruby]是一套用于执行某个任务的语句集合。 在C++中你可以定义自己的函数。 使用函数会有许多优势,包括下面列举的:
每个有效C++程序都包括至少一个函数——main()函数。 Part题: 每个C++程序都以什么函数开始? A. int() B. main C. #include D. my_function |
1.2 返回类型
main函数有如下的一般形式:
一个函数的[ruby=return type]返回类型[/ruby]在函数名前声明。上例中,返回类型是int,表示函数返回一个整型值。 有时,函数在完成操作后不会返回值。这样的函数用void关键字定义。 void是用来规定无值状态的基本数据类型。 Part题: 若一个函数没有返回值,我们该用什么关键字? |
1.3 定义函数(一)
**函数的定义遵循下面的语法:
返回类型:函数返回值的数据类型。 函数名:函数的名称。 [ruby=parameters]参数[/ruby]:当函数被调用时,你将值作为参数。这个值被叫做实际参数或实参。形参列表表明了一个函数的参数类型、顺序和数量。 函数体:一套定义函数行为的语句。 参数是可选的;意味着你可以创建没有参数的函数。 Part题: 一个C++函数的组成部分有: A. 只要返回类型 B. 无函数体的名字 C. 返回类型,函数名,形参,函数体 |
1.4 定义函数(二)
作为一个示例,我们来定义一个不返回值的函数,它只向屏幕输出一行文字:
我们的叫做printSomething的函数,返回void,且没有参数。 现在,我们可以在main()中使用我们的函数了。
要[ruby=call]调用[/ruby]一个函数,你只需函数名和所需参数。 Part题: 填空创建一个名为my_func,返回void,输出"I am a function"的函数。
|
1.5 函数(二)
在调用函数前,必须先声明它。 举例:
将声明放在main()函数之后会导致错误。 Part题: 一个函数必须在____声明。 A. 调用之前 B. 调用之后 |
1.6 函数(三)
一个函数的[ruby=declaration]声明[/ruby],或称作[ruby=function prototype]函数原型[/ruby],告诉编译器函数名和如何调用函数。实际的函数可以分开定义。 举例
当你在一个源文件定义函数,在另一个源文件调用函数时,声明是必要的。这种情况下,你应在调用函数前声明函数。 Part题: 填空输出"it works!"到屏幕,在调用前先写上函数原型。
|
2 函数参数
2.1 函数参数(一)
要让函数使用[ruby=arguments]实参[/ruby],它必须先声明[ruby=parameters]形参[/ruby],其为接受实参值的变量。 举例:
这会定义一个接受一个整型参数并输出其值的函数。 在函数内,形参与其他局部变量表现类似。它们在进入函数时创建,在离开函数时销毁。 Part题: 填空声明一个函数printValue(),接受一个参数名为x并输出其值。
|
2.2 函数参数(二)
当函数被定义后,在调用函数时可以传递对应的实参。 例:
值42作为实参传递给函数,赋给函数的形参:x。 对形参做出的修改不会影响实参。 Part题: 填空定义一个函数printValue,有一个类型为int的参数,并在main中将20作为参数传递给它。
|
2.3 函数参数(三)
你可以将不同的实参传递给同一个函数。 举例:
上面定义的函数以一个整型作为参数并返回其值乘2。 接着我们可以用不同的参数调用函数了。
Part题: 在main中调用printValue函数三次,将值4、5、6传给它。
|
3 多参函数
3.1 多个形参(一)
你可以定义你的函数需要的任意多参数,只需将参数以逗号分隔。 这是一个简单的返回两数之和的函数。
正如定义,addNumbers函数需要两个int参数,返回int。 每个形参的数据类型和名称都要标明。 Part题: 填空定义一个函数hello,接受两个参数返回int。
|
3.2 多个形参(二)
接着我们计算两个参数的和并返回结果。
Part题: 补全addNumbers函数,接受两个整型变量x和y并返回其和。和存储在answer变量中。
|
3.3 多个形参(三)
现在我们能调用了。
你也可以将返回值赋给一个变量。
Part题: 填空在main中调用addNumbers函数,参数是43和86。返回值存储在变量result中,并用cout输出到屏幕。
|
3.4 多个形参(四)
一个函数可以有任意多个参数。 例:
如果有多个形参,记住用逗号分隔,在声明时和传参时都要。 Part题: 一个函数能有多少参数? A. 一个 B. 一或二 C. 任意 |
4 rand()函数
4.1 随机数(一)
在很多情况下,能生成[ruby=random]随机[/ruby]数是很有用的,包括创建游戏、统计模型程序、以及类似。 C++标准库中,你能用到一个[ruby=pseudo]伪[/ruby]随机数生成器函数,叫做rand()。使用时,需要包含头文件<cstdlib>。
这会输出一个随机数。 Part题: 使用rand()函数需要哪个头文件? A. cstdlib B. clibstd C. crandhead D. iostream |
4.2 随机数(二)
可以用for循环生成多个随机数。
Part题: 填空在for循环中调用rand()函数并输出其返回值13次。
|
4.3 随机数(三)
用取模 (%) 运算符生成某个范围内的随机数。 下面的例子生成1-6范围内的整数。
然而,rand()函数只会返回伪随机数。这意味着每次代码运行时,它都会产生相同的数。 Part题: 填空输出1-9范围内的随机数。
|
4.4 srand()函数
srand()函数用于生成[ruby=truly]真[/ruby]随机数。 这个函数允许用其参数作为种子值,用于rand()函数的算法。
改变种子值会改变rand()函数的输出。然而,相同的参数会有相同的输出。 Part题: srand()函数的作用是? A. 无 B. 帮助生成真随机数 C. 返回其参数之和 |
4.5 真随机数
一种生成真随机数的方法是使用当前时间作为srand()函数的种子。 下面的例子利用time()函数获取你系统的当前秒数,并作为rand()种子(为此需要包含<ctime>头文件):
time(0)返回当前秒数,每次运行程序时使srand()函数为rand()函数设置不同的种子。 使用种子会让程序每次运行都有不同输出。 Part题: 填空输出rand()函数生成的1-15范围内的真随机数。
|
5 默认参数
5.1 形参默认值
定义函数时,你可以对后面的形参指定默认值。如果调用时没有对应的实参,它会使用默认值。 要这样做,用赋值运算符给函数定义中的参数赋值,如下例。
这会给形参b赋默认值42。如果调用时不给b传实参,就会使用默认值。
对函数第二次调用没有给第二个参数传值,则使用默认值42。 Part题: 填空给函数volume的参数赋默认值,假设a默认值2,b默认值3,c默认值5。
|
5.2 使用默认值
再来一个例子:
如你所见,默认参数值能用于在不同情况下调用同一参数,当一个或更多个参数没有用到时。 Part题: 下面代码的输出是?
|
6 函数重载
6.1 重载
函数的[ruby=overloading]重载[/ruby]允许创建多个同名函数,只要它们的参数不同。 举例,你也许需要一个printNumber()函数输出其参数值。
但这只对整型有效。重载它能使它对其他类型,例如浮点数,也有效。
现在,相同名称的printNumber()函数对整型和浮点数都有效了。 Part题: 填空声明函数printNumber并重载它。声明一个printNumber接受一个整型参数;另一个printNumber接受一个浮点数参数。
|
6.2 函数重载(一)
当重载函数时,不同函数的形参类型和/或形参数量必须不同。 例:
如你所见,调用时不同函数的区别与提供的实参有关。一个整型实参会解释为调用接受整型形参的函数。一个浮点数实参会调用接受浮点数形参的函数。 Part题: 两个同名函数什么时候叫做重载? A. 有不同的名字 B. 有不同的参数类型或数量 C. 有不同的函数体体积 |
6.3 函数重载(二)
你不能仅通过返回类型不同而重载函数。 下面的声明会导致错误。
尽管几个函数同名,但彼此的区别只有返回类型不同,是不允许的。 Part题: 填空重载函数sum,其接受两个数字参数并输出两数之和。对整型和浮点数重载sum函数。
|
7 递归
7.1 递归(一)
C++中的[ruby=recursive]递归[/ruby]函数指调用自己的函数。为防止递归无限运行下去,你必须写上中止条件。 Part题: 递归的思想是: A. 调用自己的函数 B. 调用main的函数 C. 声明两个变量的函数 |
7.2 递归(二)
要演示递归,我们来创建一个计算数字阶乘的程序。 数学中,“阶乘”的意思是所有小于等于给定非负整数(n)的正整数的乘积。 [ruby=Recursion is a method of solving a problem where the solution depends on the solutions to smaller instances of the same problem.]递归是一种解决某种解决方案依靠更小问题的解决方案的问题的方法。[/ruby] Part题: 5的阶乘是什么? A. 5! 等于 5 B. 5! 等于 0 C. 5! 等于 5*4*3*2*1 |
7.3 递归(三)
来写代码吧:
if语句定义了退出条件。本例中,当n等于一时,返回1(1! = 1)。 我们将递归调用部分放在else语句中,返回n乘n-1的阶乘。 举例,如果你用参数4调用factorial函数,会按照如下执行: 返回4 * factorial(3),即4 * 3 * factorial(2),即4 * 3 * 2 * factorial(1),即4 * 3 * 2 * 1。 factorial函数一直调用自身,直到参数等于1。 Part题: 填空定义一个递归函数,计算参数的阶乘。
|
7.4 递归(四)
现在我们可以调用factorial函数了。
退出条件的另一个叫法是[ruby=base case]基本情况[/ruby]。 记住对于真正的递归来说,基本情况是必要的。如果没有,递归会永远运行下去。 Part题: 一个真正的递归函数应有: A. 返回值 B. 基本情况 C. 空函数体 |
8 函数传数组为参
8.1 数组与函数(一)
数组也可以作为实参传递给函数。 声明函数时,形参应该用方括号定义为数组。 例:
填空声明一个函数printArray,接受两个参数。第一个是一个整型数组,第二个是int类型的数组大小。
|
8.2 数组与函数(二)
我们可以在main()中使用我们的函数了,用一个示例数组:
printArray函数接受数组为形参 (int arr[]),并用for循环迭代数组。 我们在main()中调用函数,将myArr数组传递给函数,输出其元素。 记住在将数组作为实参传递的时候不需要方括号。 Part题: 假设你有一个函数printArray,接受一个数组和其大小,并输出其元素。请补全代码,将一个叫做my_arr的数组传给函数。
|
9 通过指针引用传参
9.1 函数实参
调用函数时,有两种传值的方式。 [ruby=value]值[/ruby]传参:此方法将实参的值复制给函数的形参。在函数内对形参的修改不会影响实参。 [ruby=reference]引用[/ruby]传参:此方法将实参的引用复制给函数的形参。在函数内,引用用于访问实际调用函数的实参。这意味着对形参的修改会影响实参。 C++默认使用值传参方法。 Part题: 两种不同传参方式是什么? A. 引用传参和名传参 B. 引用传参和值传参 C. 值传参和名传参 |
9.2 值传参
默认情况下,C++中的实参以值传参。 当传递值时,实参的一份复制传给函数。 例:
因为传递给函数的是实参的复制,所以原参数不会被函数修改。 Part题: 值传参意味着: A. 将变量地址作为参数传递 B. 将变量的复制作为参数传递 C. 将main函数作为参数传递 |
9.3 引用传参
引用传参将实参的地址传给函数形参。在函数内,用此地址访问实际的参数。这意味着对形参的修改会影响实参。 要通过引用传参,将实参指针传递给函数。
如你所见,我们将变量用取地址运算符&直接传给函数。 函数声明说明了函数接受一个指针为形参(以* 运算符指定)。 结果,函数通过指针访问,确实改变了实参的值。 Part题: 填空将变量arg以值传参方式传给passByValue函数。
|
9.4 总结
值传参:此方法将实参的值复制给函数的形参。在函数内对形参的修改不会影响实参。 引用传参:此方法将实参的引用复制给函数的形参。在函数内,引用用于访问实际调用函数的实参。这意味着对形参的修改会影响实参。 一般来讲,值传递更快,效率更高。当你的函数需要修改实参,或需要传递一种占用大量内存且复制开销大的数据结构时引用传参。 Part题: 以引用作为形参的函数: A. 只接收到实参的复制 B. 可以修改传给它的变量 C. 是一个递归函数 |
模块检测
1. C++程序总是以哪个函数开始运行? 2. 填空声明函数printIt,输出"I love C++"到屏幕。在main中调用printIt。
3. 补全函数的形参类型,使其接受一个整型值并输出。
4. 填空声明函数sum,接受三个双精度浮点值为参数并输出其和。在main中声明三个变量a,b和c并传递给sum函数。
5. 填空声明函数myFunction,接受两个int形参,默认值分别为1和2,并输出其乘积。
6. 补全函数calcSum,接受一个数组和其大小为参数。该函数计算数组元素之和并输出。
|