- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
7.2 函数参数和按值传递
下面详细介绍一下函数参数。C++通常按值传递参数,这意味着将数值参数传递给函数,而后者将其赋给一个新的变量。例如,程序清单 7.2 包含下面的函数调用:
其中,side 是一个变量,在前面的程序运行中,其值为 5。cube( ) 的函数头如下:
被调用时,该函数将创建一个新的名为 x 的 double 变量,并将其初始化为 5。这样,cube( ) 执行的操作将不会影响 main( ) 中的数据,因为 cube( ) 使用的是 side 的副本,而不是原来的数据。稍后将介绍一个实现这种保护的例子。用于接收传递值的变量被称为形参。传递给函数的值被称为实参。出于简化的目的,C++标准使用参数(argument)来表示实参,使用参量(parameter)来表示形参,因此参数传递将参量赋给参数(参见图 7.2)。
图 7.2 按值传递
在函数中声明的变量(包括参数)是该函数私有的。在函数被调用时,计算机将为这些变量分配内存;在函数结束时,计算机将释放这些变量使用的内存(有些 C++文献将分配和释放内存称为创建和毁坏变量,这样似乎更激动人心)。这样的变量被称为局部变量,因为它们被限制在函数中。前面提到过,这样做有助于确保数据的完整性。这还意味着,如果在 main( ) 中声明了一个名为 x 的变量,同时在另一个函数中也声明了一个名为 x 的变量,则它们将是两个完全不同的、毫无关系的变量,这与加利福尼亚州的 Albany 与纽约的 Albany 是两个完全不同的地方是一样的道理(参见图 7.3)。这样的变量也被称为自动变量,因为它们是在程序执行过程中自动被分配和释放的。
图 7.3 局部变量
7.2.1 多个参数
函数可以有多个参数。在调用函数时,只需使用逗号将这些参数分开即可:
上述函数调用将两个参数传递给函数 n_chars( ),我们将稍后定义该函数。
同样,在定义函数时,也在函数头中使用由逗号分隔的参数声明列表:
该函数头指出,函数 n_char( ) 接受一个 char 参数和一个 int 参数。传递给函数的值被赋给参数 c 和 n。如果函数的两个参数的类型相同,则必须分别指定每个参数的类型,而不能像声明常规变量那样,将声明组合在一起:
和其他函数一样,只需添加分号就可以得到该函数的原型:
和一个参数的情况一样,原型中的变量名不必与定义中的变量名相同,而且可以省略:
然而,提供变量名将使原型更容易理解,尤其是两个参数的类型相同时。这样,变量名可以提醒参量和参数间的对应关系:
程序清单 7.3 演示了一个接受两个参数的函数,它还表明,在函数中修改形参的值不会影响调用程序中的数据。
程序清单 7.3 twoarg.cpp
在程序清单 7.3 的程序中,将编译指令 using 放在函数定义的前面,而不是函数中。下面是该程序的运行情况:
程序说明
程序清单 7.3 中的 main( ) 函数使用一个 while 循环提供重复输入(并让读者温习使用循环的技巧),它使用 cin>>ch,而不是 cin.get(ch)或 ch = cin.get( ) 来读取一个字符。这样做是有原因的。前面讲过,这两个 cin.get( ) 函数读取所有的输入字符,包括空格和换行符,而 cin>>跳过空格和换行符。当用户对程序提示作出响应时,必须在每行的最后按 Enter 键,以生成换行符。cin>>ch 方法可以轻松地跳过这些换行符,但当输入的下一个字符为数字时,cin.get( ) 将读取后面的换行符。可以通过编程来避开这种麻烦,但比较简便的方法是像该程序那样使用 cin。
n_char( ) 函数接受两个参数:一个是字符 c,另一个是整数 n。然后,它使用循环来显示该字符,显示次数为 n:
程序通过将 n 变量递减来计数,其中 n 是参数列表的形参,main( ) 中 times 变量的值被赋给该变量。然后,while 循环将 n 递减到 0,但前面的运行情况表明,修改 n 的值对 times 没有影响。即使您在函数 main( ) 中使用名称 n 而不是 times,在函数 n_chars() 中修改 n 的值时,也不会影响函数 main( ) 中 n 的值。
7.2.2 另外一个接受两个参数的函数
下面创建另一个功能更强大的函数,它执行重要的计算任务。另外,该函数将演示局部变量的用法,而不是形参的用法。
目前,美国许多州都采用某种纸牌游戏的形式来发行彩票,让参与者从卡片中选择一定数目的选项。例如,从 51 个数字中选取 6 个。随后,彩票管理者将随机抽取 6 个数。如果参与者选择的数字与这 6 个完全相同,将赢得大约几百万美元的奖金。我们的函数将计算中奖的几率。(是的,能够成功预测获奖号码的函数将更有用,但虽然 C++的功能非常强大,目前还不具备超自然能力。)
首先,需要一个公式。假设必须从 51 个数中选取 6 个,而获奖的概率为 1/R,则 R 的计算公式如下:
选择 6 个数时,分母为前 6 个整数的乘积或 6 的阶乘。分子也是 6 个连续整数的乘积,从 51 开始,依次减 1。推而广之,如果从 numbers 个数中选取 picks 个数,则分母是 picks 的阶乘,分子为 numbers 开始向前的 picks 个整数的乘积。可以用 for 循环进行计算:
循环不是首先将所有的分子项相乘,而是首先将 1.0 与第一个分子项相乘,然后除以第一个分母项。然后下一轮循环乘以第二个分子项,并除以第二个分母项。这样得到的乘积将比先进行乘法运算得到的小。例如,对于(10 * 9)/(2 * 1) 和(10 / 2)*(9 / 1),前者将计算 90/2,得到 45,后者将计算为 5*9,得到 45。这两种方法得到的结果相同,但前者的中间值(90)大于后者。因子越多,中间值的差别就越大。当数字非常大时,这种交替进行乘除运算的策略可以防止中间结果超出最大的浮点数。
程序清单 7.4 在 probability( ) 函数中使用了这个公式。由于选择的数目和总数目都为正,因此该程序将这些变量声明为 unsigned .int 类型(简称 unsigned)。将若干整数相乘可以得到相当大的结果,因此 lotto.cpp 将该函数的返回值声明为 long double 类型。另外,如果使用整型,则像 49/6 这样的运算将出现舍入误差。
注意:
有些 C++实现不支持 long double 类型,如果所用的 C++实现是这样的,请使用 double 类型。
程序清单 7.4 lotto.cpp
下面是该程序的运行情况:
请注意,增加游戏卡中可供选择的数字数目,获奖的可能性将急剧降低。
程序说明
程序清单 7.4 中的 probability( ) 函数演示了可以在函数中使用的两种局部变量。首先是形参(number 和 picks),这是在左括号前面的函数头中声明的;其次是其他局部变量(result、n 和 p),它们是在将函数定义括起的括号内声明的。形参与其他局部变量的主要区别是,形参从调用 probability( ) 的函数那里获得自己的值,而其他变量是从函数中获得自己的值。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论