chapter04 函数_第1页
chapter04 函数_第2页
chapter04 函数_第3页
chapter04 函数_第4页
chapter04 函数_第5页
已阅读5页,还剩27页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C 程序设计与实践 第四章函数电子科技大学信息与软件工程学院白忠建 第四章函数 本章要点函数的原型 C 编译器根据函数原型生成正确的代码 函数的参数和返回值 函数的参数和返回值可以是值 指针和引用 它们有不同的作用 函数重载 函数重载是指多个函数拥有相同的名字 但必须有不同的参数 4 1函数的原型声明和定义 函数原型 functionprototype 是一个很重要的概念 函数原型担负着三个特殊的任务 确定函数返回值的类型 使编译程序能产生函数返回数据类型的正确代码 确定了函数使用的参数的类型 个数和顺序 函数名代表该函数的函数体以及函数完成的功能 4 1函数的原型声明和定义 函数原型声明一般的语法形式为返回类型函数名 参数列表 函数的返回类型可以是任意需要的类型 函数名必须是合法的标识符 并且最好取一个有意的名字 参数列表注明各参数的名字 类型 个数和顺序 而这里的参数是形式参数 形参 如果函数没有参数 那么参数列表位置可以写上关键字void 或者直接空缺 4 1函数的原型声明和定义 函数声明的例子 voidCircle intxCenter intyCenter intradius 函数声明中的参数名字可以省略 voidCircle int int int 函数原型也称为函数的 接口 interface 函数声明不是一个函数的全部 它还需要实现部分 实现部分由函数的定义完成 4 2函数的参数和返回值 4 2 1函数的参数函数的参数称为 形式参数 简称形参 在编译时 形式参数不具有任何实际的值 这些值需要在运行时通过函数调用的形式 将实际的值 称为 实际参数 简称实参 传递给形式参数 以便完成需要的运算 这个过程称为 形参和实参的结合 4 2函数的参数和返回值 1 参数结合的三种方式1 传值C 采用传值 callbyvalue 方式进行参数传递 也就是说 在参数结合时 形参是实参的一个复制品 形参和实参是两个不同的单元 这样 形参的改变不会影响实参 这样的形参往往也被称为 值参数 或者 输入参数 4 2函数的参数和返回值 1 参数结合的三种方式1 传值C 采用传值 callbyvalue 方式进行参数传递 也就是说 在参数结合时 形参是实参的一个复制品 形参和实参是两个不同的单元 这样 形参的改变不会影响实参 这样的形参往往也被称为 值参数 或者 输入参数 例4 1 两个变量交换值 ex4 1 cpp 4 2函数的参数和返回值 2 传指针传递指针实际上仍属于传值的范畴 形参指针是实参指针的拷贝 不过 这两个指针指向了同一个单元 因此 通过这两个指针的任何一个都可以间接地改变实参的值 例4 2 两个变量交换值 ex4 2 cpp 4 2函数的参数和返回值 3 传引用实参和形参结合的第三种也是最好的一种方法就是传递引用 我们都知道 引用是一个单元的别名 这种别名结合也适用于参数结合 当形参是一个引用时 那么在函数内部 形参就是实参的别名 换句话说 形参就是实参本身 因此对形参的改变就会直接改变实参 提示 引用形参与实参的别名绑定不是永久性的 而只在函数作用范围内起作用 例4 2 两个变量交换值 ex4 2 cpp 4 2函数的参数和返回值 2 const作用于参数使用指针和引用参数具有实参被更改的潜在 危险 为了避免这种危险 可以给形参加上const约束 这是形参 实参成为只读参数 从而避免了被更改的问题 例如 voidfunc constint pi inta pi 正确 pi 0 错误 因为pi指向的单元被视为常量pi 正确 因为pi不是常量指针 4 2函数的参数和返回值 3 缺省参数C 有缺省参数的概念 它是另外一种形式的函数重载 例如 voidfun intnum 0 其中 num称为 缺省参数 0称为 缺省值 那么在调用函数fun时 num对应的实参可以有 也可以没有 缺省 fun 10 传递显式的值 则num的初始值为10fun 无对应的实参 则num的初始值为0 4 2函数的参数和返回值 3 缺省参数所有取缺省值的参数都必须出现在不取缺省值的参数的右边 亦即 一旦开始定义取缺省值的参数 就不可以再说明非缺省的参数 例如 voidf1 intx 10 inty errorvoidf2 intx inty 0 okvoidf3 intx 10 inty 0 ok例4 3 缺省参数 ex4 3 cpp 4 2函数的参数和返回值 4 2 2函数的返回值函数是一个完成一定功能的程序块 在很多时候需要将计算的结果传递给调用该函数的程序块 传递结果的方式之一就是让函数返回一个值 我们先来看看函数原型的声明 返回类型函数名 参数列表 这里的返回类型就是函数返回值的类型 它可以使任意的合法类型 4 2函数的参数和返回值 1 函数返回值类型函数返回一个值类型 实际上是将返回的值放到一个临时对象中 调用者可以拷贝临时对象的值以供以后使用 intStrlen constchar str char p const cast str while p 0 p returnp str 函数Strlen 返回一个整数值 这个值被存储在一个临时变量 对象 中 临时对象是匿名的 并且被当做常量 因此不能作为左值使用 4 2函数的参数和返回值 2 函数返回指针函数返回指针 实际上也是返回一个值 只不过这个值是某个单元的地址 char Strcat constchar str1 constchar str2 char str newchar Strlen str1 Strlen str2 1 char p str while p str1 copyeverycharacterintostr includingendingNULL p sostepbackwhile p str2 returnstr 因为函数内部分配了一些内存 所以函数的使用者应该在适当的时候利用函数返回的指针释放掉这段内存 由于函数返回的指针要被调用者使用 因此在调用者还在使用指针时 该指针指向的对象必须还是有效的 否则会导致灾难性的结果 4 2函数的参数和返回值 3 函数返回引用函数返回引用 实际上返回的是一个对象 是个左值 只不过是匿名的 因此 如果一个函数返回引用的话 则函数调用可以出现在赋值号的右边 也可以出现在赋值号的左边 例4 4 函数返回引用 ex4 4 cpp 与返回指针一样 函数返回的引用单元也必须在被调函数返回后一直有效 4 2函数的参数和返回值 4 3函数重载当两个或多个在相同范围内的声明用的是同一个名字时 这个名字就被称为 重载 overloading 在C 中 只有函数能够被重载 其中包括运算符函数 例如 doubleabs doublenum return num 0 num num longabs longnum return num 0 num num 4 2函数的参数和返回值 虽然两个函数拥有相同的名字 但它们的参数类型是不同的 其实 只要编译器能区分参数的类型 或者参数的个数 那么就可以重载一个函数 函数重载有以下禁忌 仅返回值类型不同而其它部分相同的函数不能重载 同一个作用域中的函数不能原型一致地重载 如果要重载 那么必须在参数列表上有所不同 4 3函数重载 1 重载声明由于函数重载只以参数作为参考点 因此这里就对重载函数的参数进行一些说明 例子中的重载函数是不能被接受的 1 用typedef定义的类型别名与原类型等效 例如 typedefintINT voidf inti 函数定义voidf INTi 错误 重定义f函数 2 指针和数组参数是等效的 例如 voidg int voidg int 与g int 一样voidg int 5 与g int 一样 3 函数参数和函数指针参数是等效的 例如 voidh int voidh int 与h int 一样 4 在函数调用时编译器无法区分cv 修饰符 例如 voidk int voidk constint 错误 重定义k int 5 不同函数的对应参数仅是缺省参数的不同时 它们是等效的 例如 voidp inti 0 voidp voidq p 错误 调用的是p int 还是p 4 3函数重载 2 重载匹配方案在调用重载函数是 编译器会首先查询与给定参数类型和个数完全匹配的重载版本 例如 函数调用abs 1 0 会匹配abs double abs 1L 会匹配abs long 但abs 1 0f 会匹配哪一个呢 4 2函数的参数和返回值 当编译器无法精确匹配参数时 隐式转换规则会起作用 此例中 float型的值1 0f可能会被隐式转换成为1 0 或者1L 而在这两种转换方案中 从float类型转换成double类型是最佳匹配方案 因此编译器会选择abs double 这个版本 但在有的时候 编译器可能无法判断哪种转换方案为佳 例如有函数调用abs 1 整型值1将使编译器陷入两难境地 到底是转换成1 0好呢 还是1L好 两个方案都一样好 这使得编译器无法抉择 因此只好报出一个错误 4 4存储类修饰符 C 的存储类修饰符有五种 分别是 autoregisterstaticexternmutable 4 5标识符的作用域和生命期 4 5 1作用域和生命期一个程序空间定义了一个全局作用域 globalscope 简称 全局域 属于该程序的任何语法成分都被定义在这个唯一的全局域中 一个名字空间 一个类和一个全局函数又定义了各自的局部作用域 localscope 类的成员函数 属于局部函数 也会定义一个嵌入在类作用域中的局部函数作用域 而函数 包括全局函数 中的语句块也会定义一个嵌入在外层函数作用域中的局部块域 实际上 用一种简单的观点来看 除全局域外 一对花括号 就定义了一个作用域 而在最外层 之外 就是全局作用域 4 5标识符的作用域和生命期 任何一个标识符 亦称名字 都会被定义在某个作用域中 这样一来 这个标识符的作用域和生命期就被完全局限在包围它的作用域中 一旦超过这个作用域访问标识符将会引起错误 前面的代码中不包含标识符a的定义a 0 错误 使用了未定义的标识符 定义了一个作用域的开始inta a的作用域和生命期从其定义开始a 1 正确 作用域的结束 标识符a的作用域和生命期也随之结束 a 错误 超过了作用域 对象a已经失效 4 5标识符的作用域和生命期 4 5 2名字限定在上一小节的代码中 我们已经使用了一种限定的名字 qualifiedname a 作用域解析运算符 指明了名字a来自于全局作用域 可以用名字限定的方式指名名字来自于其它的作用域 这些作用域包括名字空间 类 限定的名字有如下的语法形式 作用域名 标识符如果上述标识符来自于一个嵌套的作用域 那么限定名字的语法形式为 外层作用域名 嵌套作用域名 标识符 4 6函数的其他话题 4 6 1内联函数inlinelongabs longnum return num 0 num num 4 6函数的其他话题 4 6 2函数递归函数递归 recursion 指得是一个函数直接或者间接调用自己的现象 例4 5函数递归 ex4 5 cpp 4 6函数的其他话题 Reverse 是如何工作的 设输入 abc 从main进入voidReverse charc cin c a if c return Reverse cout c 第一次递归进入voidReverse charc cin c b if c return Reverse cout c 第二次递归进入voidReverse charc cin c c if c return Reverse cout c 第三次递归进入voidReverse charc cin c i

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论