




已阅读5页,还剩117页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第8章函数8 1概述一个C程序 由一个主函数和若干其它函数组成 它们之间的关系是 主函数可以调用其它函数 其它函数可相互调用 且一个函数可以被调用若干次注 每个函数都是独立的 平等的 函数 完成特定功能的程序段 通常由用户定义或系统定义各函数可存放在一个文件中 也可以存放在不同的文件中 某程序整体结构 程序运行轨迹 main a d a e a main b f e f b g b h b main c h g h c i c main 举例 用常规 文件包含两种方法打印字符串一 常规方法 各函数包含在一个文件中例T8 1 cmain p1 p2 p1 p1 printf n p2 printf How do you do n 运行结果 How do you do 二 文件包含的方法在主函数所在的文件中使用文件包含预编译命令 将不在本文件而在其它文件中的函数进行预编译处理 把各文件中的函数包含到本文件中来 然后一起进行编译 连接 运行 T8 1 3 c include T8 1 1 c include T8 1 2 c main p1 p2 p1 运行结果同上友情提示 还可以用项目的方法 T8 1 1 cp1 printf n T8 1 2 cp2 printf How do you do n 说明 1 一个文件可含多个函数 编译的单位是文件而不是函数 2 一个完整的程序可由若干个文件组成 可用项目或文件包含的方法对其编译 3 C执行总是从main函数开始执行 调用其它函数后又返回到main函数 4 函数定义是独立的 平等的 不能嵌套定义 即函数里不能再定义函数 但可相互调用 5 函数的类型 标准库函数 由系统提供 用户直接使用 用户定义的函数 6 函数的形式 无参函数主调函数无数据传给被调函数 可带或不带返回值 有参函数主调函数与被调函数间有参数传递 主调函数可将实际参数传送给被调函数的形式参数 被调函数的函数值可传回主调函数 8 2函数定义的一般形式1 无参函数的定义形式 类型标识符函数名 声明部分语句部分 注 无参函数一般不返回函数值 故类型标识符可省 2 有参函数的定义形式 类型标识符函数名 形式参数表列 声明部分语句部分 其中 类型标识符 指出函数返回值的数据类型 int float char等 系统默认为int函数名 合法的标识符 形参表列 接收主调函数传递过来的实参 其中包括对形参类型的声明 老版本中形参类型进一步声明放在下一行 形参类型 与实参类型要一致 称函数体 包括声明部分 定义局部变量的数据类型 语句部分 完成函数功能的若干执行语句 例 intmax intx inty intz z x y x y return z 3 空函数的定义形式类型说明符函数名 例 p1 空函数不作任何操作 但是合法 它对调试程序或以后在此处补充完整的函数体是有作用的 4 对形参声明的传统方式传统方式中 形参类型说明在函数定义的第2行如 传统形参声明形式intmax x y intx y intz z x y x y return z 新版本形参声明形式intmax intx inty intz z x y x y return z 以上两种定义形式在TurboC中都认可 8 3函数参数和函数的值8 3 1形式参数和实际参数实际参数 主调函数中提供的数据 可以是常量 变量 表达式等 是具体的数值 形式参数 被调函数中用以接收主调函数数据的变量 被调用函数名后面括号内的若干变量名 例T8 2 c调用函数时的数据传递main inta b c scanf d d 输入 100200 Maxis200 关于形 实参的说明 1 形参只有在函数调用时才分配存储单元 调用结束后 释放所分配的单元 2 实参可以是常量 变量 表达式 max 3 a b 总之要有确定的值 当函数调用时 将实参的值传递给形参 若是数组名 则传送的是数组的首地址 3 被调函数中 形参类型必须指定 以便分配存储单元 4 实参 形参的数据类型一致 赋值要兼容 顺序要一致 如果形 实参类型不一致时 则按赋值规则进行 通常被调函数放在主调函数之前 以便编译系统对函数类型和形参类型作合法性检查 若被调函数在主调函数之后 一般要对被调函数作原型声明 main floata 4 5 b 4 5 intabc int int abc a b abc intx inty printf x d y d n x y 结果 x 4 y 4 5 若被调函数类型为非整形或实参形参类型不匹配 要在主调函数中对被调函数作原形声明 另外若被调函数在主调函数之前定义 则原形声明可省 因为编译系统已经知道被调函数的类型及其形参的个数 类型了 6 实参对形参的数据传送是值传送 也是单向传送 当被调函数的形参发生变化时 并不改变主调函数实参的值 例T8 2 1 c形 实参占据的是不同的存储单元main inta 2 b 3 printf a d b d n a b printf 运行结果 a 2 b 3 a ffd6 b ffd8x 10 y 15 x ffd2 y ffd4a 2 b 3 a ffd6 b ffd8 8 3 2函数的返回值调用一个函数一般都希望返回一个确定的值 有关函数值的几点说明 1 若需要返回值则用return语句 2 被调函数中可用多个return语句 执行哪一个由程序执行情况来定 例 函数中有如下语句if a b return a elsereturn b 3 return后面的括号可省 如 returna 4 return后的值可以是一个表达式 如 return x y x y 5 函数值的类型是在定义函数时指定的如 intmax x y floatmin a b doubleabc d1 d2 6 语句return a b c 是合法的 返回表达式c的值 注意 1 函数定义时 函数名的括号后无 2 未加类型说明的函数自动按整型处理 3 定义函数时 函数值的类型一般与return后面表达式的类型一致 若不一致 则以函数值为准 例T8 3 c函数值类型为整型 而返回值的类型是实型 最后以整型值返回 即以函数类型为准main intmax float float 原型声明 floata b intc scanf f f 输入 1 52 5 输出 maxis2 6 函数中无return语句时 可能返回一个不确定或无用的值例T8 3 1 cmain inta b c a p1 b p2 c p1 printf a d b d c d n a b c p1 printf n p2 printf Iamhappy n 运行结果 Iamhappy a 6 b 12 c 6 7 为明确表示不带返回值 可用void 无值 空类型 定义函数 例T8 3 2 cmain inta b c a p1 b p2 c p1 printf a d b d c d n a b c voidp1 printf n voidp2 printf Iamhappy n 编译时指出 Typemismatchinredeclartionof p1 p2 意即 在定义函数p1 p2时类型不匹配 8 4函数的调用主调函数 主动去调用其它函数被调函数 被其它函数所调用8 4 1函数调用的一般形式函数名 实参表列 操作 把控制和实参传送给被调函数 当无参时 实参表列为空 但 不能省 函数名 是已存在的被调用的函数 实参表列 有确定值的数据 当有多个实参时 实参间用 分隔 通常形实 参个数要相等 类型要一致 实参求值顺序在TurboC中是从右向左 例T8 4 c实参求值顺序从右向左main inti 2 p p f i i printf p d i d n p i intf inta intb intc if a b c 1 elseif a b c 0 elsec 1 return c 运行结果 p 0 i 3若将参数改为f i i 则结果为 p 1 i 3思考 若从左至右呢 回忆一下printf的求值顺序 8 4 2函数的调用方法1 函数语句 把函数调用作为一个单独的语句 如 f1 2 函数表达式 函数调用出现在表达式中 其函数返回的值参加整个表达式的运算 如 c max a b min c d 3 函数参数 函数调用作为另一个函数的参数 如 m max a max b c printf d max a b 8 4 3对被调用函数的声明和函数原型被调函数应具备的条件1 被调函数必须存在 标准或用户定义 如不在同一文件中 可用项目或文件包含的方法将各被调用函数连接起来 2 若使用库函数 应在文件开头用 include命令将调用库函数时用到的宏定义信息包含到本文件中来 如 include stdio h include math h 3 若主调和被调函数在同一文件中 一般应在主调函数中对被调函数的类型作声明 即向编译系统声明即将调用的函数形式 类型标识符被调用函数名 类型形参 例T8 5 c在主调函数中 对被调函数的数据类型进行说明main floatadd floatx floaty 声明 函数类型 名 形参类型等通知编译系统 再看floata b c scanf f f 输入 3 66 5输出 sumis10 10000 问题 1 若不对函数类型进行声明 则指出 在重定义函数add时 类型不匹配 2 在声明时指出类型 若定义时没有指出类型 编译指出 定义add时类型不匹配 此处是实型 函数声明 原型 与函数首部一致 顺序 个数 类型等都要相同有关函数的定义 声明 返回值等概念1 函数定义 对函数功能的确定 指定函数名 函数值类型 形参及类型 函数体等 它是完整的 独立的函数单位 2 函数声明 也称函数原型 其作用是把函数的名字 函数类型以及形参的类型 个数和顺序通知编译系统 以便调用函数时进行对照检查 函数声明 原型 的形式 1 函数类型函数名 参数类型1 参数类型2 2 函数类型函数名 参数类型1参数名1 参数类型2参数名2 3 当函数返回的值为整型或字符型时 可不必声明 系统会默认把第一次碰到的函数视为INT4 被调用函数在主调函数之前定义时 在主调函数中可不必声明 友情提示1 函数的原型声明必须放在程序开始处或main之前 例T8 5 1 c被调函数出现在主调函数之前 则在主调函数中不必声明floatadd floatx floaty floatz z x y return z main floata b c scanf f f 输入 3 66 5输出 sumis10 100000 主调函数中没对被调函数的返回值进行类型声明 原因是 编译系统已经预知定义的函数的类型 并进行自动处理 5 如果在所有函数定义之前 在文件的开头 在函数的外部对函数的类型作了声明 则在各主调函数中不必对所调用的函数再作类型声明 例T8 5 2 c在文件的开头 在所有函数的外部对函数作类型声明 chara1 charx1 charx2 floata2 floaty1 floaty2 inta3 intm doublea4 doublen1 doublen2 main 返回 charc1 d c2 a inti 5 floatf1 3 67 f2 5 56 doubled1 11111111 111 d2 22222222 222 printf a1 c n a1 c1 c2 printf a2 f n a2 f1 f2 printf a3 d n a3 i printf a4 lf n a4 d1 d2 chara1 charx1 charx2 return x1 x2 x1 x2 floata2 floaty1 floaty2 floatz z y1 y2 return z inta3 intm inti s 1 for i 1 i m i s s i return s doublea4 doublen1 doublen2 doublen3 n3 n1 n2 return n3 运行结果 a1 da2 9 230000a3 120a4 33333333 333000问题的提出 1 不在文件开头 不在函数外部说明 情况如何 2 不在主调函数开始部分说明 解决的办法 友情提示2 不要将空函数和void函数弄混了 8 5函数的嵌套调用 例T8 6用弦截法求方程x3 5x2 16x 0的根 请仔细研究 方法与步骤 2 连接f x1 f x2 两点成一直线 弦 此线交x轴于x X点的坐标求法 连接f x1 f x2 两点的直线f x 称商差 弦 斜率 求x点的坐标 从x值得f x 3 若f x 与f x1 同号 则根必在 x x2 区间 此时将x作新的x1 若f x 与f x2 同号 则根必在 x1 x 区间 此时将x作新的x2 4 重复步骤2 3直到 f x 为止 设 10 6 则f x 0 异号 x1 x2之间必有一根1 取x1 x2两点得f x1 f x2 同号 改变x1 x2 直到f x1 f x2 异号为止 用三个函数实现各部分的功能 f x 用来求x的函数 x3 5x2 16x 80 xpoint x1 x2 求f x1 与f x2 的连线 弦 与x轴交点x的坐标 root x1 x2 求 x1 x2 区间的实根例T8 6 c用弦截法求方程x3 5x2 16x 80的根 include math h floatf floatx floaty y x 5 0 x 16 0 x 80 0 return y floatxpoint floatx1 floatx2 floaty y x1 f x2 x2 f x1 f x2 f x1 return y floatroot floatx1 floatx2 floatx y y1 y1 f x1 do x xpoint x1 x2 y f x if y y1 0 y1 y x1 x elsex2 x while fabs y 0 0001 return x main floatx1 x2 f1 f2 x do printf inputx1 x2 n scanf f f 运行 inputx1 x2 2 6Arootofequationis5 0000 8 6函数的递归调用递归 在函数调用过程中 直接或间接的调用自身 1 直接递归 在函数体内又调用自身 2 间接递归 当函数去调用另一函数时 而另一函数反过来又调用自身 解决无终止递归调用的方法是 确定好结束递归的条件 递归调用定义 函数直接或间接的调用自身叫函数的递归调用 说明C编译系统对递归函数的自调用次数没有限制所以 必须要用if语句限制递归的次数 以免无限递归下去了 intf intx inty z z f y return 2 z 例T8 7 c有5个人在一起问年龄 第5个人比第4个人大2岁 第4个人比第3个人大2岁 第2个人比第1个人大2岁 第1个人为10岁 回推 递推 T8 7 c问年龄程序age intn intc if n 1 c 10 elsec 2 age n 1 return c 返回给主调函数 main printf d n age 5 运行结果 18 在递归调用过程中 有些信息被临时压入堆栈回推到已知 结束这里控制有限次递归的一个条件就是if n 1 有些问题 可以用递推 也可以用递归的方法解决 递推 从一个已知的事实出发 按一定规律推出下一个事实 再从已知的新的事实 推出下一个新的事实 例T8 7 1 c用递推法求n 即从1开始 乘2 乘3 一直到nmain inti s 1 for i 1 i 5 i s s i printf s d n s 运行结果 s 120 递归 回推 问题先压入堆栈暂存 递推从哪里开始递推 从满足结束递归的条件处开始递推如 5 5x4 4 4x3 3 3x2 2 2x1 1 10 1 例T8 8 c用递归法求4 floatfacto intn floats if n 0 printf n 0dataerror n elseif n 0 n 1 s 1 elses n facto n 1 return s main intn floaty printf inputaintegernumber scanf d facto intn ints if n 0 s 1 else s facto n 1 s n s return s facto intn ints if n 0 facto intn ints if n 0 s 1 else s facto n 1 s n s return s s facto n 1 facto intn ints if n 0 facto intn ints if n 0 s 1 else s facto n 1 s n s return s s facto n 1 facto intn ints if n 0 s 1 else s facto n 1 s n s return s facto intn facto intn ints ints if n 0 if n 0 s facto n 1 s 1 return 1 s n s 2 1 return 2 return 6 s n s 3 2 s n s 4 6 return 24 1 2 3 4 3 2 1 N 4 N 3 N 2 N 1 facto intn ints if n 0 s 1 else s facto n 1 s n s return s facto intn ints else s facto n 1 2 N 4 main函数第1次调用facto main 堆栈 n 4 facto intn ints if n 0 s 1 else s facto n 1 s n s return s N 3 facto intn ints else s facto n 1 3 Facto1函数第2次调用facto main 堆栈 n 4 n 3 facto intn ints if n 0 s 1 else s facto n 1 s n s return s N 2 facto intn ints else s facto n 1 4 Facto2函数调用第3次facto main 堆栈 n 4 n 3 n 2 facto intn ints if n 0 s 1 else s facto n 1 s n s return s N 1 facto intn ints else s facto n 1 4 Facto3函数第4次调用facto main 堆栈 n 4 n 3 n 2 n 1 facto intn ints if n 0 s 1 else s facto n 1 s n s return s s 1 N 0 facto intn ints if n 0 Facto4函数第5次调用facto return 1 main 堆栈 n 4 n 3 n 2 n 1 facto intn ints if n 0 s 1 else s facto n 1 s n s return s s facto 1 1 0 1 s 1 1 return 1 N 1 main 堆栈 n 4 n 3 n 2 恢复facto4现场 40E2 n 1 0 1 facto intn ints if n 0 s 1 else s facto n 1 s n s return s s facto 2 1 1 1 s 2 1 return 2 N 2 main 堆栈 n 4 n 3 恢复facto3现场 40E2 n 2 1 1 facto intn ints if n 0 s 1 else s facto n 1 s n s return s s facto 3 1 2 2 s 3 2 return 6 N 3 main 堆栈 n 4 恢复facto2现场 2 2 40E2 n 3 facto intn ints if n 0 s 1 else s facto n 1 s n s return s return 24 N 4 s facto 4 1 3 6 s 4 6 main 堆栈 恢复facto1现场 3 6 40E2 n 4 返回主函数 例T8 9 chanoi 汉诺 塔问题 请仔细研究 十九世纪未 欧洲珍奇商店出现一种汉诺塔游戏 并有推销材料 说是古代印度布拉玛庙里的僧侣们当时正在玩这种游戏 如果游戏结束 世界未日即来临 一 规则及分析 n个盘子从一个座移到另一个座 每次只能移动一个盘子 不允许大盘在小盘上面 共有三个座 n个盘子由A座移到C座 需移动的次数是2n 1 若64个盘子移动的次数为 264 1 18 446 744 073 709 551 615一年的秒数是 365x24x60 x60 3153600018446744073709551615 31536000 584942417355年即 5849亿年 从能源角度推算 太阳系寿命只有150亿年 二 方法与步骤1 将A上n 1个盘子借助C座移到B座2 把A上剩下一个盘子送到C座3 将n 1个盘子从B座借助A座移到C座 三 实例 将A上3个盘子移到C步骤 1 A座上两个盘子借助C座移到B座2 A座上最后一个盘子移到C座3 B座上两个盘子借助A座移到C座第一步进一步分解 1 1A座上一个盘子从A C1 2A座上一个盘子从A B1 3C座上一个盘子从C B第二步进一步分解 A座上最后一个盘子从A C第三步进一步分解 3 1B座上一个盘子从B A3 2B座上一个盘子从B C3 3A座上一个盘子从A C 结论 1 3步都是把n 1个盘子从一个座移到另一个座上 方法一样 只是座的名称不同而已 为使之一般化 将1 3步表示为 将one座上的n 1个盘子移到two座 借助three座 只是对应关系不同 第一步对应关系 one Atwo Bthree C第三步对应关系 one Btwo Cthree A 1 将n 1个盘子从一个座移到另一个座上 n 1 2 将1个盘子从一个座移到另一个座上 n 1 例T8 9 c用递归的方法解决汉诺塔程序如下 voidmove charx chary printf c c n x y voidhanoi intn charone chartwo charthree if n 1 move one three else hanoi n 1 one three two move one three hanoi n 1 two one three main intm printf inputthenumberofdiskes scanf d 运行 inputnumberofdiskes 3 thesteptomoving3diskes A CA BC BA CB AB CA C 8 7数组作为函数参数函数调用形式一 函数名 数组名 实参或形参函数调用形式二 函数名 数组元素 实参数组名作为参数 传递的是数组的首地址 数组元素作实参时 传递的是数组元素的值 是单向的值传送 8 7数组作为函数参数函数调用形式一 函数名 数组名 实参或形参函数调用形式二 函数名 数组元素 实参数组名作为参数 传递的是数组的首地址 数组元素作实参时 传递的是数组元素的值 是单向的值传送 数组元素作函数实参 值传递 例两个数组大小比较 n 0m 0k 0 a和b为有10个元素的整型数组比较两数组对应元素变量n m k记录a i b i a i b i a i k 认为数组a b若n k 认为数组a b若n k 认为数组a b 2 数组名作为函数实参此时 传送的是数组的地址 调用函数时 对形参数组元素的操作 实际上也是对实参数组元素的操作 地址传递 在主调函数与被调函数分别定义数组 且类型应一致 例求学生的平均成绩 includefloataverage intstu 10 intn voidmain intscore 10 i floatav printf Input10scores n for i 0 i 10 i scanf d floataverage intstu 10 intn inti floatav total 0 for i 0 i n i total stu i av total n returnav 实参用数组名 形参用数组定义 intstu 几点说明 1 数组名作形 实参数时 应分别在主 被调函数中对其定义2 数组名作参数时 传递的是地址 对形参数组的操作实际上也是对实参数组的操作 两个数组是共用同一个内存单元 则形参中的数据变化了实参也会变化 这与变量做形参区别很大3 作为形 实参数的数组 其类型要一致 大小一般相等 以保证形式上的对应 4 当形参数组大小未指定时 用一实参将数组长度传递给形参以便对数组进行操作 5 字符串的传递同数组的传递 字符串是用数组存储的 例8 12 c求两组学生的平均成绩 形参数组长度缺省floataverage floata intn inti floataver sum a 0 for i 1 i n i sum sum a i aver sum n return aver main floats1 5 98 5 97 91 5 60 60 55 floats2 10 67 5 89 5 99 69 5 77 89 5 76 5 54 60 99 5 printf theaverageofclassAis 6 2f n average s1 5 printf theaverageofclassBis 6 2f n average s2 10 theaverageofclassAis80 40theaverageofclassBis78 20 例数组元素与数组名作函数参数比较 includevoidswap2 intx inty intz z x x y y z main inta 2 1 2 swap2 a 0 a 1 printf a 0 d na 1 d n a 0 a 1 值传递 includevoidswap2 intx intz z x 0 x 0 x 1 x 1 z main inta 2 1 2 swap2 a printf a 0 d na 1 d n a 0 a 1 地址传递 例数组元素与数组名作函数参数比较 例数组排序 简单选择排序 请同学们自行思考 9 49 i 0 例数组排序 简单选择排序 13 68 i 1 i 8 例数组排序 简单选择排序 例求二维数组中最大元素值 intmax value intarray 3 4 inti j k max max array 0 0 for i 0 imax max array i j return max main inta 3 4 1 3 5 7 2 4 6 8 15 17 34 12 printf maxvalueis d n max value a 例求二维数组中各行元素之和 get sum row intx 3 intresult introw intcol inti j for i 0 i row i result i 0 for j 0 j col j result i x i j main inta 2 3 3 6 9 1 4 7 intsum row 2 row 2 col 3 i get sum row a sum row row col for i 0 i row i printf Thesumofrow d d n i 1 sum row i 18 12 8 8局部变量和全局变量8 8 1局部变量变量 按其作用域 可分为局部和全局局部 作用域仅限于其所定义的函数或复合语句内部 离开该函数或复合语句则释放内存单元特点 1 在不同的函数中允许同名 它们占据不同的内存单元 相互之间互不影响 2 形参属局部变量 只能在其所在的函数内部使用 例T8 14 1 cf1 inta 10 b 25 c 30 printf f1 a d b d c d n a b c f2 inta intb intc a a 2 c a b 3 printf f2 a d b d c d n a b c main inta 1 b 2 c 5 abc也不例外 也是局部变量 printf 1 main a d b d c d n a b c f1 printf 2 main a d b d c d n a b c f2 a b printf 3 main a d b d c d n a b c 运行结果 1 main a 1 b 2 c 5f1 a 10 b 25 c 302 main a 1 b 2 c 5f2 a 3 b 2 c 83 main a 1 b 2 c 5 例T8 14 2 c复合语句中局部变量的例子main inta 1 b 2 c 3 intc c a b printf a d b d c d n a b c printf a d b d c d n a b c 运行结果 a 1 b 2 c 1a 1 b 2 c 3 8 8 2全局变量全局变量 在一个文件的所有函数以外定义的变量称为外部或全局变量 作用域 从定义变量的位置开始到源程序结束 所有该源文件中的函数公用 几点说明 在源程序开始定义的全局变量 对源程序中所有函数有效 在源程序中间定义的全局变量 仅对其后面的所有函数有效 几点说明2 在函数或复合语句中定义的局部变量若与全局变量同名 当该函数或复合语句被执行时 则局部变量优先 全局变量不起作用 被屏蔽 例T8 14 3 c全局变量的作用域及其使用情况inta 1 f1 intb b a 3 printf f1 a d b d n a b f2 inta b a 5 b a 3 printf f2 a d b d n a b f3 intb a 6 b a 3 printf f3 a d b d n a b main intb 3 printf 1 main a d b d n a b f1 printf 2 main a d b d n a b f2 printf 3 main a d b d n a b f3 printf 4 main a d b d n a b 运行 1 main a 1 b 3f1 a 1 b 42 main a 1 b 3f2 a 5 b 83 main a 1 b 3f3 a 6 b 94 main a 6 b 3 几点说明3 全局变量的使用 增加了函数间数据联系的渠道 同一文件中的所有函数都能引用全局变量的值 当某函数改变了全局变量的值时 便会影响其它的函数 例T8 15 c用一维数组存放10个学生的成绩 在函数中求最高分 最低分和平均值 floatmax 0 min 0 习惯上 Max Min floataverage floatarray intn inti floataver sum array 0 max min array 0 for i 1 imax max array i elseif array i min min array i sum sum array i aver sum n return aver main floatave score 10 inti printf input10numbers n for i 0 i 10 i scanf f 一个函数可以返回3个值了 运行 input10numbers 9945789710067 589926643 max 100 00min 43 00ave 77 65 floatmax min floataverage floatarray intn inti floatsum array 0 max min array 0 for i 1 imax max array i elseif array i min min array i sum array i return sum n main inti floatave score 10 Input ave average score 10 printf max 6 2f nmin 6 2f naverage 6 2f n max min ave 外部 全局 变量的弊端 1 建议非必要时不要使用全局变量 1 整个程序中均占用存储空间 2 函数可移植性差2 程序可读性差 且一旦外部变量被改变将影响所有函数 inti main voidprt for i 0 i 5 i prt voidprt for i 0 i 5 i printf c printf n 例外部变量副作用 运行结果 变量的存储属性概述每个变量有两个基本属性 变量的数据类型 那么 变量的存储类型呢 编译或函数调用时为其分配内存单元 10 程序中使用变量名对内存操作 变量的属性数据类型 变量所持有的数据的性质 操作属性 存储属性存储器类型 寄存器 静态存储区 动态存储区生存期 变量在某一时刻存在 静态变量与动态变量作用域 变量在某区域内有效 局部变量与全局变量变量的存储类型auto 自动型register 寄存器型static 静态型extern 外部型变量定义格式 存储类型 数据类型变量表 如 intsum autointa b c registerinti staticfloatx y 程序运行时 在内存中的存储情况 1 静态存储方式 即程序运行期间为其分配的存储单元是固定的 直到文件执行完 2 动态存储方式 程序运行期间根据需要为其分配存储单元 用完就释放 格式 autointa 说明符 auto 可以省略 autofloatpi 说明 1 说明自动变量必须在一个函数体的内部 2 函数的形参也是自动变量 作用域函数内部 实质上是一个局部变量 只有在函数被调用时才存在 从函数中返回时即消失 其值仅限于说明它的函数 由于自动变量具有局部性 所以在两个不同的函数中可以分别使用同名的变量而互不影响 自动变量auto 8 9 2auto变量函数内部无static声明的局部量均为动态存储类别 被分配在动态区 自动存储类别的声明符auto可省 自动变量被分配在动态区 每次调用重新分配空间 用完释放 其值也消失 例如 intf inta autointb c 3 定义b c为自动变量 上述变量定义与以下定义等价 intb c 3 8 9 3用static声明局部变量若希望函数调用结束后 其值不消失 下次调用函数时继续使用上次已有的值 则用static对变量加以声明 思考 全局变量需要专门声明static吗 例T8 17 c考察静态局部变量的值f inta autointb 0 staticintc 3 b b 1 c c 1 return a b c main inta 2 i for i 0 i 3 i printf d f a 运行结果 789 静态局部变量的声明 1 分配在静态区 程序运行结束才释放存储单元 与动态的区别 2 仅开始时 编译时 划好房间赋初值一次 未赋初值时为0 以后每次调用函数时 变量不再赋值 直接使用前次操作的结果 与动态的区别 3 局部动态变量若未赋初值 其值是不确定的 所分配的存储单元是不固定的 而局部静态变量未赋初值 编译时赋其值为0 字符型变量的值为 0 所分配的存储单元是固定的 4 静态局部变量在函数调用结束后虽存在 但其它函数不能引用它 使用局部静态变量有如下几种情况 1 需要保留上一次调用结束时的值例T8 18 c打印1 5的阶乘值intfac intn staticintf 1 f f n return f main inti for i 1 i 5 i printf d d n i fac i 返回 2 初始化后变量只被引用而不改变其值 则用静态局部变量较方便 以免每次调用都要赋初值 缺点 从程序运行开始到结束一直占用内存 这样会浪费系统资源 问题 1 将static改为auto2 其它函数能否使用局部静态变量 8 9 4register变量简介 cpu构造 degug演示 CPU和内存之间数据交换及速度 CacheCPU内部有寄存器组可用来存放数据 若把数据声明为寄存器类型 则将该类型的数据暂存放在寄存器中 其优点在于 减少数据与内存之间的交换频率 提高程序的效率和速度 例T8 19 c使用寄存器变量intfac intn registerinti f 1 for i 1 i n i 思考 和staticf在程序上的区别 f f i return f main inti for i 1 i 5 i printf d d n i fac i 好处 n 10000000 运行结果 1 12 23 64 245 120 例 C74 08 Cmain registerinttemp i for i 0 i 10000 i for temp 0 temp 30000 temp printf ok n 9 4变量的存储类型与作用域 续 例 比较下面两个程序的运算速度 main registerinttemp i for i 0 i 30000 i for temp 0 temp 10000 temp printf ok n 寄存器类型变量的几点说明 1 局部自动类型和形参可定义为寄存器类型 全局 静态的变量不可以 why 因为要释放 2 使用寄存器类别的变量个数与系统有关 在Turboc中与自动变量的个数一致 整型数据类型的寄存器变量可定义32500个 实型数据类型的寄存器变量可定义16300个 如此看来并没有把它们存放在寄存器中 3 Turboc中 register变量作auto变量处理 4 寄存器类型的变量不允许对其地址操作 5 不能将静态变量定义为寄存器变量 两者只能占其一6 实际上用register是没必要的 系统会自动识别 按需分配 8 9 5用extern声明外部变量外部变量也称全局变量 在函数外部定义 其作用域是从变量的定义处开始 到本程序文件的未尾 在定义的作用域内 全局变量可为程序中各个函数所引用1 在一个文件内部声明外部变量 例T8 20用extern声明外部变量 扩展程序文件中的作用域intmax intx inty intz z x y x y return z main externA B 等价于externintA B printf d max A B intA 13 B 8 运行结果 13 2 在多文件的程序中声明外部变量当一个程序由多个文件组成时 要在一个文件中引用另一文件中的外部变量时 此时要用extern加以声明 若在两个文件中同时对同名的外部变量定义 则系统连接时将提示 重定义类型错 例 给定b值 输入a和m 求a b和am 例T8 21用extern将外部变量的作用域扩展到其它文件 include T8 21 1 c intAmain intpower int intb 3 c d m printf enterthenumberaanditspowerm n scanf d d 输入 33输出 3 3 93 3 27 8 9 6用static声明外部变量若使全局变量只限于定义它的文件中的函数引用 而不让其它文件中的函数引用 需要用static加以说明 注意 此种说法只在项目方法中有效 而在文件包含中则不起作用 例T8 21 2 c include T8 21 3 c staticintA main A 5 printf A1 d n A f1 printf A4 d n A 例T8 21 3 cexternintA f1 printf A2 d n A A A A printf A3 d n A 说明 1 在运行T8 21 2 c时 无论有无stat
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2021年人民警察节活动训练学习心得与体会五篇
- 2025年教师招聘之《幼儿教师招聘》题库必背100题含答案详解(精练)
- 教师招聘之《幼儿教师招聘》综合提升测试卷及答案详解(典优)
- 2025年教师招聘之《小学教师招聘》通关提分题库及完整答案详解【各地真题】
- 教师招聘之《幼儿教师招聘》考试彩蛋押题附答案详解【模拟题】
- 教师招聘之《幼儿教师招聘》自测题库及参考答案详解(模拟题)
- 2025年教师招聘之《小学教师招聘》通关提分题库附答案详解【培优】
- 实商务英语综合教程(第一册)-课件 Unit 9 Business Environment
- 2025年新能源商用车辆在电力运输中的应用场景分析报告001
- 教师招聘之《幼儿教师招聘》练习题(一)附参考答案详解【典型题】
- 2025年山东高考真题化学试题(原卷版)
- 2025湖南湘潭市市直事业单位招聘(选调)工作人员48人考试参考试题及答案解析
- 第2课 教师节快乐 第2课时(课件)2025-2026学年道德与法治二年级上册统编版
- 2025年福建省福州市辅警考试题库(附答案)
- 2025年国家网络安全宣传周知识竞赛考试练习题库(完整版)含答案
- 绿化项目养护监理方案投标文件(技术方案)
- 科普短视频与新闻传播融合模式的研究
- 2025秋新部编版一年级上册语文教学计划+教学进度表
- 大学英语四级高频词汇1500+六级高频词汇1500
- GB/T 20841-2007额定电压300/500V生活设施加热和防结冰用加热电缆
- 测井曲线综合解释(课堂PPT)
评论
0/150
提交评论