




已阅读5页,还剩49页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C语言程序设计,第8章 函数(2),8.5 函数的嵌套调用,语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下一级函数的问题。 语言允许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用。 即在被调函数中又调用其它函数。这与其它语言的子程序嵌套的情形是类似的。,main() x=add(a,b); ,float mul(float x1) return(x1*x1); float add(float x1,floatx2) y1=x1+ mul (x2) ; return y1; ,函数的嵌套调用 x=a+b*b,8.6 函数的递归调用,1、递归的概念 直接递归调用 调用函数的过程中又调用该函数本身 间接递归调用 调用f1函数的过程中调用f2函数,而f2中又需要调用f1。 以上均为无终止递归调用。 为此,一般要用if语句来控制使递归过程到某一条件满足时结束。,四、函数的递归调用,2、递归算法 类似于数学证明中的反推法,从后一结果与前一结果的关系中寻找其规律性。 归纳法可以分为: 递推法 从初值出发,归纳出新值与旧值间直到最后值为止的关系。 要求通过分析得到: 初值+递推公式 编程:通过循环控制结构实现(循环的终值是最后值) 递归法 从结果出发,归纳出后一结果与前一结果直到初值为止的关系。 要求通过分析得到: 初值+递归函数 编程:设计一个函数(递归函数),这个函数不断使用下一级值调用自身,直到结果已知处选择控制结构。,四、函数的递归调用,2、递归算法,其一般形式是: 在主函数中用终值n调用递归函数,而在递归函数中: 递归函数名f(参数x) if (n=初值) 结果=; else 结果=含f(x-1)的表达式; 返回结果(return); ,f(x) f(x-1) ,main() f(n) ,f(x-1) f(x-2) ,f(x-2) f(x-3) ,f(x0) f(x0= ) ,【例8.6】有5个人,第5个人说他比第4个人大2岁,第4个人说他对第3个人大2岁,第3个人说他对第2个人大2岁,第2个人说他比第1个人大2岁,第1个人说他10岁。求第5个人多少岁。,()() ()() ()() ()() () 可以用数学公式表述如下:,通过分析,设计递归函数如下: 10 (n=1) age(n)= age(n-1)+2 (n1),age(int n) int c; if (n=1) c=10; else c= age(n-1) +2; return c; main() printf(“%d“,age(5); ,程序如下:,请看看单步运行的情况,age(5) c=age(4)+2; return c;,age(int n) int c; if (n=1) c=10; else c=age(n-1)+2; return c; ,递归过程 跟踪分析:,age(4) c=age(3)+2; return c;,age(3) c=age(2)+2; return c;,age(2) c=age(1)+2; return c;,age(1) c=10 return c;,c=10,c=12,c=14,c=16,c=18,【例8.7】用递归法求n! 分析比较:,实际上,递归程序分两个阶段执行 回推(调用):欲求n! 先求 (n-1)! (n-2)! 1! 若1!已知,回推结束。 递推(回代):知道1!2!可求出3! n!,阶乘的递推算法:,对于一个非负整数,它的阶乘是以下表达式的结果: n!=1*2 *(n-3)*(n-2)*(n-1)*n n!= n* (n-1)* (n-2)* (n-3)* *2*1 递推(或称迭代法)算法 例如5的阶乘: 5!=5*4*3*2*1 for ( i=1,result=1; i= 5; i+) result *= i;,阶乘的递推算法示例:,#define N 10 #include “stdio.h“ void main() int i, result; printf(“%d! = “,N); for ( i=1, result=1; i=N; i+) printf(“%d“,i); result *= i; if(iN) printf(“*“); printf(“= %d“,result); ,阶乘的递归算法:,n!= n* (n-1)* (n-2)* (n-3)* *1 递归算法 例如5的阶乘: 5!= 5* (4*3*2*1) = 5* 4! 4!= 4* (3*2*1) = 4* 3! 3!= 3* (2*1) = 3* 2! 2!= 2* 1 = 2* 1! 1!= 1,阶乘的递归算法示例:,#include “stdio.h“ long fac(int n) long c; if (n=0 | n=1) c=1; else c=n*fac (n-1); return c; main() long n,s; printf(“Input n=“); scanf(“%d“, ,/递推法 long fac (int n) long i,c=1; for(i=1; i=n;i+) c=c*i; return c; ,/递归法 long fac (int n) long c; if (n=0 | n=1) c=1; else c=n*fac (n-1); return c; ,8.7 数组作为函数参数,数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式, 1. 把 数组元素(下标变量) 作为实参使用; 2. 把 数组名 作为函数的形参和实参使用。 数组元素作函数实参 数组元素就是下标变量,它与普通变量并无区别。 因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。,例:判断整数数组中各元素的值,若大于0 则输出该值0,若小于0则输出0,若等于0,则输出=0。编程如下:,#include “stdio.h“ void func(int a) if(a0) printf(“%d 0 n“,a); else if (a=0) printf(“%d =0n“,a); else printf(“%d 0n“,a); void main() int a5,i; printf(“input 5 numbers:n“); for(i=0;i5;i+) scanf(“%d“, ,用数组元素作实参时,只要数组类型和函数的形参变量的类型一致,那么作为下标变量的数组元素的类型也和函数形参变量的类型是一致的。 因此,对数组元素的处理是按普通变量对待的。,数组名作为函数参数,用数组名作函数参数时,要求形参和相对应的实参都必须是类型相同的数组,都必须有明确的数组说明。 当形参和实参二者不一致时,即会发生错误。,数组名作为函数参数,在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。 在函数调用时发生的值传送是把实参变量的值赋予形参变量。 在用数组名作函数参数时,不是进行值的传送,即不是把实参数组的每一个元素的值都赋予形参数组的各个元素。 实际上形参数组并不存在,编译系统不为形参数组分配内存。,那么,数据的传送是如何实现的呢? 在我们曾介绍过,数组名就是数组的首地址。 因此在数组名作函数参数时所进行的传送只是地址的传送,也就是说把实参数组的首地址赋予形参数组名。 形参数组名取得该首地址之后,也就等于有了实在的数组。 实际上形参数组和实参数组为同一数组,共同拥有一段内存空间。,上图中设a为整型实参数组。a占有以2000为首地址的一块内存区。 当发生函数调用时,进行地址传送,把实参数组a的首地址传送给形参数组名b,b也取得该地址2000。 于是a,b两数组共同占有以2000为首地址的一段连续内存单元。 从图中还可以看出a和b下标相同的元素也占相同的内存单元。 例如a0和b0都占用同一内存单元,a0等于b0。类推则有ai等于bi。,#define SIZE 3 #include “stdio.h“ void func(int b) /定义func函数,形式参数为数组 int i; for(i=0;i0) printf(“%d 0 n“,bi); else if (bi=0) printf(“%d =0n“,bi); else printf(“%d 0n“,bi); void main() int aSIZE,i; printf(“input %d numbers:n“, SIZE); for(i=0;iSIZE;i+) scanf(“%d“, /调用func函数,实际参数为数组名 ,解析:编写一个函数用来删除指定字符,可以将字符串中的字符除了指定字符外,全部赋给另一个字符串,则delstr中必须要有两个形参数组,要知道需要删除第几位,必须要一个int整型的形参。 子函数定义:void delstr (char a, char b, int n) 输出新串时没有必要从子函数中传递数值回主函数,只要打印新串就可以了。,#include “stdio.h“ #define LEN 40 void main() void delstr(char a, char b, int n); char str1LEN, str2LEN; int n; puts(“请输入一个字符串“); gets(str1); printf(“请问要删除第几位的字符:“); scanf(“%d“,void delstr(char a, char b, int n) int i,j=0; for(i=0; jLEN; i+) if (i!=n) bj=ai; j+; ,变量的存储类型,变量两大属性: 数据类型 存储类别,2、存储类别 规定了变量在计算机内部的存放位置决定变量的“寿命”(何时“生”,何时“灭”) C程序的存储类别有: register型(寄存器型) auto型(自动变量型) static型(静态变量型) extern型(外部变量型) 一个完整的变量说明格式如下: 存储类别 数据类型 变量名 如 auto int x , y ;,C程序的变量存储位置,变量的生存期 静态存储区中的变量:与程序“共存亡” 动态存储区中的变量:与函数“共存亡” 寄存器中的变量:与动态存储区相同,存储在动态存储区的变量:, register型(寄存器型) 变量值存放在运算器的寄存器中存取速度快,一般只允许23个,且限于char型和int型,早期通常用于循环变量。 auto型(自动变量型)(变量的默认类型) 只有需要它们时才占用内存,即定义变量的函数被调用时,auto型变量才被创建,函数结束时,变量立刻被删除。 优点节约内存同一内存区可被不同变量反复使用。 以上两种变量均属于“动态存储型”,即调用函数时才为这些变量分配单元,函数调用结束其值自动消失。,静态变量,静态变量是静态存储类型的变量,即在程序运行期间分配固定的存储单元,它永久存在,不随函数的退出调用而释放。 在所有函数之外定义的静态变量是静态外部变量。 未初始化的静态外部变量在编译时自动初始化为零值。,存储在静态存储区的变量:, static型(静态变量型) 变量值存放在主存储器的静态存储区 程序执行开始至结束,始终占用该存储空间 extern型(外部变量型) 同上,其值可供其他源文件使用 以上两种均属于“静态存储”性质,即从变量定义处开始,在整个程序执行期间其值都存在(都可用!),未说明存储类别时, 函数内定义的变量默认为auto型 函数外定义的变量默认为extern型。,外部变量,在所有函数之外定义而没有指定其存储类别的变量称为外部变量,即全局变量。 连接在一起的各目标文件的源程序文件中的所有函数均可以访问外部变量。,外部变量, 外部变量是静态存储类型的变量,在程序运行期间分配固定的存储空间,因此其生存期是整个程序的运行期,就是说它的值不随函数的退出调用而消失。 外部变量可在定义时作初始化;没有初始化的外部变量,由编译程序自动初始化为零值。,在一个文件内声明外部变量,如果外部变量不在文件的开头定义,其有效的作用范围只限于 定义处到文件终结处。 如果在定义点之前的函数想引用该外部变量,则应该在引用前用关键字 extern 对该变量作“外部变量声明”。表明该变量是一个已经定义的外部变量。,局部变量与全局变量,1、局部变量函数内部或复合语句内定义的变量,auto(默认) 所在函数调用结束时,其值自动消失 局部变量 register 如不赋初值,取不确定值为初值 static 所有函数调用结束,其值仍保留 如不赋初值,取初值为0(数值型)或空格(字符型),所有形参都是局部变量; 局部变量只在本函数或本复合语句内才能使用,在此之外不能使用(视为不存在)main函数也不例外。,局部变量与全局变量,2、全局变量在函数之外定义的变量,extern(默认)允许本源文件中其他函数及其他源文件使用 全局变量 static 只限本源文件中使用,所有全局变量加不加static,都属于静态存储,如不赋初值,取初值为0(数值型)或空格(字符型) (注意与函数内部定义的static型局部变量的区别),2、全局变量在函数之外定义的变量,有效作用范围:从定义变量位置开始直到本源文件结束 如果需要将全局变量的作用范围扩展至整个源文件 方法1 全部在源文件开头处定义 方法2 在引用函数内,用extern说明变量 方法3 在源文件开头处,用extern说明变量,【例】求程序运行结果 extern int x,y; main( ) printf(“x=%d,y=%dn“,x,y); int x=100, y=200;,结果:x=100,y=200,去掉第一行试试,#include “stdio.h“ void use_local(); void use_static_local(); void use_global(); int x=1; int main() int x=5; printf(“主函数中x = %dn“,x); int x=7; printf(“主函数中的复合语句中的x = %dn“,x); printf(“主函数中的复合语句外的x = %dnn“,x); use_local(); use_static_local(); use_global(); use_local(); use_static_local(); use_global(); printf(“主函数中的x = %dn“,x); return 0; ,void use_local() int x=25; printf(“use_local()中x的初值为 = %dn“,x); x+; printf(“use_local()中x 在调用结束前的值 = %dnn“,x); void use_static_local() static int x=50; printf(“use_static_local()函数中x的初值为 = %dn“,x); x+=2; printf(“use_local()中x 在调用结束前的值 = %dnn“,x); void use_global() printf(“use_global()函数中x的初值为 = %dn“,x); x*=10; printf(“use_global()中x 在调用结束前的值 = %dnn“,x); ,主函数中x = 主函数中的复合语句中的x = 主函数中的复合语句外的x = use_local()函数中x的初值为 = use_local()函数中的x 在函数调用结束前的值 = use_static_local()函数中x的初值为 = use_local()函数中的x 在函数调用结束前的值 = use_global()函数中x的初值为 = use_global()函数中的x 在函数调用结束前的值 = use_local()函数中x的初值为 = use_local()函数中的x 在函数调用结束前的值 = use_static_local()函数中x的初值为 = use_local()函数中的x 在函数调用结束前的值 = use_global()函数中x的初值为 = use_global()函数中的x 在函数调用结束前的值 = 主函数中的x =,主函数中x = 5 主函数中的复合语句中的x = 7 主函数中的复合语句外的x = 5 use_local()函数中x的初值为 = 25 use_local()函数中的x 在函数调用结束前的值 = 26 use_static_local()函数中x的初值为 = 50 use_local()函数中的x 在函数调用结束前的值 = 52 use_global()函数中x的初值为 = 1 use_global()函数中的x 在函数调用结束前的值 = 10 use_local()函数中x的初值为 = 25 use_local()函数中的x 在函数调用结束前的值 = 26 use_static_local()函数中x的初值为 = 52 use_local()函数中的x 在函数调用结束前的值 = 54 use_global()函数中x的初值为 = 10 use_global()函数中的x 在函数调用结束前的值 = 100 主函数中的x = 5,main() int a=2,i; for (i=0;i3;i+) printf(“%4d“,f(a); f(int a) int b=0; static int c=3; b+;c+; return a+b+c; ,【例一】求程序运行结果,变量跟踪 main( ) f函数 a i b c f(a) 2 0 01 4 7 1 01 5 8 2 01 6 9 【结果】 7 8 9,如果去掉static呢?,【结果】 7 7 7,main() int k=4,m=1,p; p=func(k,m); printf(“%d,“,p); p=func(k,m); printf(“%d“,p); func(int a,int b) static int m=0,i=2; i+=m+1; m=i+a+b; return m; ,【例二】求程序运行结果,main() int k=4,m=1,p; p=func(k,m); printf(“%d,“,p); p=func(k,m); printf(“%d“,p); func(int a,int b) int m=0,i=2; i+=m+1; m=i+a+b; return m; ,main() int k=4,m=1,p; p=func(k,m); printf(“%d,“,p); p=func(k,m); printf(“%d“,p); func(int a,int b) static int m=0,i=2; i+=m+1; m=i+a+b; return m; ,【例二】求程序运行结果,变量跟踪 main( ) func函数 k m a b m i 4 1 4 1 08 23 4 1 4 1 817 312 【结果】 8, 17,如果去掉static,【结果】 8, 8,int a=3,b=5; max(int a,int b) int c; c=ab?a:b; return c; main() int a=8; printf(“%dn“,max(a,b); ,【例】求程序运行结果,如果主函数中没有int a=8,结果?,【结果】 5,如果让主函数中int a=4或a=-1,结果?,【结果】 均为 5,【结果】 8,void num() extern int x,y; int a=15,b=10; x=a-b; y=a+b; int x,y; main() int a=7,b=5; x=a+b; y=a-b; num(); printf(“%d,%dn“,x,y); ,【例】比较两个程序的运行结果,void num() int x,y; int a=15,b=10; x=a-b; y=a+b; main() int x,y; int a=7,b=5; x=a+b; y=a-b; num(); printf(“%d,%dn“,x,y); ,void num() int x,y; int a=15,b=10; x=a-b; y=a+b; int x,y; main() int a=7,b=5; x=a+b; y=a-b; num(); printf(“%d,%dn“,x,y); ,【例】求程序运行结果,如果第二行不加上extern,【结果】 5,25,【结果】 12,2,int n=1; func(); main( ) static int x=5; int y; y=n; printf(“MAIN: x=%d y=%d n=%dn“, x, y, n); func( ); printf(“MAIN: x=%d y=%d n=%dn“, x, y, n); func( ); func( ) static int x=4; int y=10; x=x+2; n=n+10; y=y+n; printf(“FUNC: x=%d y=%d n=%dn“, x, y, n); ,/*x 静态局部变量*/,/*函数声明*/,/*函数调用*/,/*全局变量 n */,/* x, y静态局部变量,x初值=5;*/,/*y=1 5 1 1 */,课堂练习:写出下列程序的执行结果,课堂练习,猴子吃桃问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第十天早上在想吃时,就只剩一个桃子了。求第一天共摘了多少个桃子? 分别用递推和递归法编程计算。,算法,总天数 10天 最后一天是1个 每一天吃前一天的一
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 大班骑车活动方案
- 地产春季暖场活动方案
- 大学口腔活动方案
- 夏日购买汽车活动方案
- 夫妻论坛活动方案
- 大班厨房活动方案
- 圣诞节蛋糕活动方案
- 基本反射活动方案
- 2025-2030极端气候船舶对高耐蚀钢板市场需求预测报告
- 夏季送西瓜活动方案
- DL∕T 1917-2018 电力用户业扩报装技术规范
- 上海高中历史合格考知识点填空讲解
- 古建筑测绘智慧树知到期末考试答案章节答案2024年长安大学
- 广东省深圳市宝安区2023-2024学年五年级下学期期末英语试题
- 心力衰竭药物治疗相关高钾血症防治专家共识
- JT-T-496-2018公路地下通信管道高密度聚乙烯硅芯塑料管
- 2-2-1正常新生儿的特点及疾病预防的正常新生儿的特点
- 抚顺三支一扶真题2023
- 青岛版四年级下册科学期末测试试卷
- 01467-土木工程力学(本)-国开机考参考资料
- 世界文化美学导论智慧树知到期末考试答案章节答案2024年南开大学
评论
0/150
提交评论