函数与宏定义

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

7
6.4
函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身, 称为函数的递归调用。 例6.4 有5人排成一队,从最后一人开始,其年龄均比前面的人大2 岁,而最前面的人年龄是10岁,问最后一人的年龄是多少岁?
Main( )
age(5)
age( ) n=5
age(4)+2
age( ) n=4
age(3)+2 age(1)=16
age( ) n=3
age(2)+2 age(1)=14
age( ) n=2
age(1)+2 age(1)=12
age( ) n=1
age(1) =10 age(1)=10
输出age(5) age(1)=18
//6_4让程序单步执行,仔细观察执行流程,分析结果!!! #include<stdio.h> int age(int n) { int c; printf("here is age function begin!\n"); if(n==1) {c=10; printf("The first is %d_here is age function \"c=10;\"!\n",c); } else {c=age(n-1)+2; printf("%d__here is age function \"c=age(n-1)+2;\"!\n",c); } printf("here is age function end!\n"); return c;} void main() {printf("here is main function begin!\n"); printf("The last is %d years old\n",age(5)); printf("here is main function end!\n");} 2014-3-2 9
采用递归方式解决古印度汉诺塔(Tower of
设开始前A座上圆盘编号从上至下依次为1,2,3…n
Hannoi)问题。
#include<stdio.h> int step=0; void hnt(int n,char a,char b,char c) {if(n==1) //最低复杂度时:程序出口 {step++; printf("%d:1th:%c---->%c\n",step,a,c); //搬第1个从a座到c座 return; //回代 } //以下为递归形式 hnt(n-1,a,c,b); //降低复杂度从a座借c座搬n-1个到b座:直接递归 step++; printf("%d:%dth:%c---->%c\n",step,n,a,c); //搬第n个从a座到c座 hnt(n-1,b,a,c); //降低复杂度也可从b座借a座搬n-1个到c座:直接递 归 } void main() {int num=3; 2014-3-2 13 hnt(num,'A','B','C');
写出下面程序的运行结果: 例6.4 e #include "stdio.h" fun(int x) {int p; if(x==0||x==1) return 3; p=x-fun(x-2); return p; } void main() { printf("%d\n",fun(9)); }
结果为:7
分析如下程序函数的调用、形参空间开辟、值传递、返回、及 空间释放流程。 例6.1 从键盘输入两个整数,输出其中较大的一个。 #include<stdio.h> void main( ) { int a,b,c; scanf("%d,%d",&a,&b); int max(int,int); /*函数声明*/ c=max(a,b); /*函数调用*/ printf("Max is %d\n",c); a 2 b 5 c 5 } int max(int x,int y) /*函数定义*/ { int z; ① ① ③ z=x>y?x:y; return z; ② x 2 y 5 z 5 }
Age(4–1)+2
Age(5–1)+2 Age(5) 出栈
14+2=16
16+2=18
18
出栈结果
10
总结:递归是一种逻辑思维方法、是分析问题解决问题的有效
手段!适用递归方法解决的问题具备如下特点: 可以逐步降低问题的复杂度(规模)、每一步的算法(递归形式) 是相同的! 递归过程不应无限制地进行下去,应当能在有限次递归以后就 达到递归的终点(递归终止条件),得到一个确定结果(程序出口)! 然后将结果逐步回代而得到最终结果! 递推是从已知、逐步推导出最终结果。 可用如下通用的算法编写递归(函数) fun(deg,…) : ①运行fun(deg,…)试图解决复杂度为deg的问题; ②若deg满足递归终止表达式END(least_deg,…)、运行 g(least_deg,…)解决复杂度为least_deg(最低)的问题,返回! 进入逐步回代阶段、使复杂度逐步提升的问题依次解决而得到 最终结果! ③若deg不满足递归终止表达式END(least_deg,…)、修改(降低) 复杂度;以新的复杂度转①(可间接或直接递归)。 2014-3-2
输出结果: 0
6
例6.3 编程求11~999之间的数m,而m、m2和m3均是回文数(数 位左右对称)。 如:m=11、m2=121、m3=1331,…… 。 #include<stdio.h> void main() {long int m; int fun(long n); for(m=11;m<1000;m++) if(fun(m)&&fun(m*m)&&fun(m*m*m)) printf("m=%-5ldm*m=%-7ldm*m*m=%ld\n", m,m*m,m*m*m);} int fun(long n) {long i,k; i=n; k=0; while(i) {k=i%10+k*10;i=i/10;} if(k==n) return 1; else2014-3-2 return 0;}
函数的递归调用利用了堆栈技术。在本例中: Age(2 Age(3 Age(4 Age(5 –1)+2 Age(5)
Age(2–1)+2
Age(3–1)+2
Age(2–1)+2
Age(3–1)+2
10+2=12
12+2=14
Age(4–1)+2
Age(5–1)+2 Age(5) 入栈
2014-3-2
6.1 C函数的定义格式:
Baidu Nhomakorabea
例: int max(x,y) int x, y; { int z; z=x>y ? x : y; return z; }
/各形式参数类型说明 / /函数体中的其它变量说明 /
turbo c 中写成一行两 行都行;在vc中要写成 一行; int max(int x, int y)
2014-3-2
例6.2 从右至左计算各实参的值并将其传递! #include<stdio.h> void main() {int i=2,p; 注意:这里是按自右至左 int fun(int,int ); 求值的,相当于fun(3,3)。 p=fun(i,++i); 若按自左至右求值,则相 printf("%d\n",p); 当于fun(2,3), 则输出为-1。 } int fun(int a,int b) {int c; if(a>b) c=1; else if(a==b) c=0; else c=-1; 2014-3-2c;} return
C允许定义空函数:
类型说明符 函数名( ) { }
"空函数"什么操作也不做。其作用是在此处留一函数 的位置,以便将来扩充功能之用。函数名也在将来换 取实际的函数名。 2014-3-2 2
6.2 函数原型(function prototype)
函数原型反映了函数名、函数返回值的数据类型、各形参类 型及出现次序等信息!如上例中的函数原型表述为: int max(int,int) C编译利用函数原型检查函数调用的合法性(不关注形参名), 实际上函数定义中已包含函数原型;C的库函数的函数原型在相 应的头文件中说明。将函数原型加上分号变成了函数声明语句! 函数定义在后、调用函数之前必须进行函数声明;这也是以前调 用库函数时包含相应头文件的理由。
2014-3-2 15
#include<stdio.h> int c=0; //定义外部变量c void main() {int a=3,b,c=1; //局部变量c同名外部变量 if(c) //使用局部变量c {int a=5; //块变量a同名局部变量 b=a+c; //使用块变量a printf("b=%d\n",b);} b=a+c; //使用局部变量a printf("b=%d\n",b); printf("c=%d\n",c); int add(int a); add(a);} int add(int a) {c+=a; //使用外部变量c printf("c=%d\n\n",c); return c;} 2014-3-2
6.5 作用域与存储属性
6.5.1.C程序构成:
一个C程序可由多个C文件构成(头文件或源文件)、一个C 文件可由多个C函数构成、一个C函数可由多个语句或语句块(用 大括号括起来的多条语句)构成。 6.5.2作用域 函数的代码和函数体内定义的变量(称之为局部变量或自动 变量)是封装在一起的的,不能被其它函数中的任何语句(除调用 它的语句之外)所访问;也不能把一个函数定义于另一个函数内 部。函数外可以定义变量、称之为外部变量或全局变量。"语言 的作用域规则"是在整个源程序范围内确定一个函数或一个变量 是否可以被访问(或称之为是否"可见")的一组规则。
6.3 函数调用
函数调用的一般形式: 函数名(实参表); 函数定义时()内的参数称为形式参数、函数调用时()内参数称 2014-3-2 3 为实际参数。
调用函数前实参必须有确定的值、实参可以为表达式,C编译 会从右至左计算各实参的值并将其传递给相应的形式参数;原则 上、实参个数及其类型与形参一一对应! 只有在函数被调用时C编译才会为形参及函数内定义的其它变 量分配内存空间,函数返回后占用空间被释放! 如果函数有返回值、可以将函数调用语句置于其它表达式之中、 当然可以置于赋值号右边(返回值为void不允许),参与运算的是 函数的返回值。如果return语句后表达式的值与函数原型中返回 值类型不一致,则以函数原型为准,系统自动进行类型转换。 函数调用经历了从主调函数到被调函数的执行控制,系统至少应 保存主调函数函数调用处或下一语句地址(断点)以便从被调函数 返回!被调函数中return语句可以有多条,但只要return被执行返 回值即被带回并返回断点;若被调函数无返回值,被调函数函数 体的右大括号启动返回。 2014-3-2 4
•类型标识符定义了函数返回值 的数据类型,无return语句时 类型标识符 函数名(形式参数表) 应定义为void; 各形式参数类型说明; •函数的返回值为return后表达 式的值; { 说明部分 ; •没有形参的函数称之为无参函 语句; 数; return 表达式; •可在()中同时说明形参名及其 } 2014-3-2 1 类型。
C语言的变量必须先定义再使用、而且只能定义一次;定义 语句建立了程序实体,其定义位置确立了实体的原有作用域。 局部变量只能在定义它的函数内可见、具有函数作用域,因 此不同函数中可以使用相同名字的变量而对应着不同的程序实 体且互不干扰;形式参数也是局部变量。 在函数中复合语句内定义的变量只在该块中可见、具有块 作用域,与本函数中定义的局部变量同名时、局部变量在块中 不可见。 外部变量又称全局变量、从定义变量的位置开始到本源文件 结束可见、具有文件作用域,与本文件中的局部变量(或块变量) 同名时、在局部变量(或块变量)的作用域内、外部变量不可见。 函数从定义好后的位置开始到本源文件结束都可直接调用。 分析下面程序的运行结果:
第6章
函数与宏定义
函数是C的基本模块单元,一个函数通常设计为完成一个特 定任务且它的名字最好与其任务相关联。除main()函数只能被操 作系统调用外、函数可以相互调用;可以将被调函数想象为一 个"黑盒子",如果需要、它可以接受函数调用时给定的输入参数, 按设定的步骤处理数据,如果需要、也可以返回一个值给主调 函数。 •函数名符合标识符命名规则;
相关文档
最新文档