C语言 模块化程序设计
可用两种方式调用函数: (1) 函数的调用可以在允许表 达式出现的任何地方。如:
c=fmax( a , b ); (2) 函数调用可以作为一条独 立的语句。比如,有函数定义:
void printstar( )
{ printf(“***************”);
} 则可以把该函数调用作为一个 独立语句,
• 函数说明是一条语句,它指 出函数返回值的类型、函 数的名称、函数要接收的 参数的个数、顺序和类型。 • 如果在一个函数中要调用 另外一个函数,则在调用 之前要对该函数进行说明。
6
3.函数定义
4.2 函数的声明、定义和调用
▪ 函数定义的一般形式:
函数值类型 函数名(形参表) /*函数头*/
{ /*函数体*/
k(3)=k(2) ×3
k(3)=2×3=6
k(2)=k(1) ×2 k(2) = 1×2=2
k(1) = 1 图4-6 回推和递推过程
20
4.3 函数的多级调用
int k(int n) /*递归计算函数*/
{
int m;
/*m存放函数的返回值*/
if(n = = 1) m = 1;
else if(n % 2 = = 0) m = k(n - 1) * 2;/*调用自身,n为偶数*/
printstar();
8
4.2 函数的声明、定义和调用
▪ 函数返回值
▪ 函数返回值的类型是由函 数定义或说明中的函数返 回类型决定的。如果返回 的类型与函数说明的不同, 则在返回值时,先作隐含 的类型转换,然后再返回。
#include <stdio.h> int fmax(float x , float y) {
int fibonacci(int n)
{
if(n ==0 || n == 1) return 1;
else return fibonacci( n – 1 ) + fibonacci( n – 2 );
22
}
【例4-8】反向输出一个长整数 ▪ 程序设计思路:
4.3 函数的多级调用
(1) 如果要输出的数据只有一位,则“反向输出”问题可简化为 输出一位整数。
说明部分
执行部分
} float fmax(float x , float y)
函数头
{
float z;
z = x > y ? x : y;
return z; }
函数体
7
4.函数调用
4.2 函数的声明、定义和调用
▪ 函数调用的一般形式为:
函数名(实参表);
void main() {
float a , b , c; scanf( “%f,%f”, &a , &b ); c = fmax(a , b); printf( “max=%f\n”, c ); }
▪ 要求:
➢ 第8周上课前提交
27
1.程序在内存中的分布区域
4.4 变量的作用域和存储类别
(1) 程序区:存放用户程序代码,即程序中各个函数的代码。
(2) 静态存储区:存放程序的全局数据和静态数据。分配在静态 存储区中的变量的生命期最长,它们在main函数运行之前就 存在了,在程序的整个活动期(从程序开始执行到执行结束) 中,这些变量始终占用静态存储区中对应的存储空间,即程 序开始执行时分配存储单元,程序执行完毕后释放。
14
4.3 函数的多级调用
main函数 { ……
t1=min2(-2,8);
t2=min3(-2,8,-6);
…… }
min3函数 { ……
x=min2(a,b);
…… }
min2函数 { ……
return a<b?a:b;
…… }
图4-5 函数调用关系
15
2.递归调用
4.3 函数的多级调用
▪ 递归调用指的是一个函数执行过程中出现了直接或间接调用 函数本身的调用方式。如果直接调用函数本身称为直接递归; 如果调用了另外一个函数,那个函数又调用该函数,则称为 间接递归。
25
▪ 练习: ➢ 1.函数fun实现计算两个数之差的绝对值,并 将差值返回调用函数,请编写fun函数 fun(int x, int y).
26
▪ 第7周作业: ➢ 1.在主函数中输入三角形的的三条边,调用子 函数,判断是否能组成三角形,若可以则返回1 否则返回0。在主函数中输出判断结果。 ➢ 2.编写函数,求两个正整数m和n的最大公约数。 m 和 n 作为函数的参数。函数返回运算结果,由 主函数输出。 ➢ 4. 习题4.2
▪ 递归方法的基本思想是将一个问题向下分解具有同样解决方 法但规模不断缩小的子问题,不断进行这样的分解,直到分 解的子问题有一个已知解。
某数列为k(n)的定义为:
1
n=1
k(n)= 2×k(n-1) n为偶数
3×k(n-1) n为奇数
19 函数的多级调用
k(4)=6×2=12
1,1,2,3,5,8,13,21……
▪ 程序设计思路:
(1) 求Fibonacci数列第n项的值可用递归形式定义为:
fibonacci (0) = 1
fibonacci (1) = 1
fibonacci (n) = fibonacci (n - 1) + fibonacci (n - 2)
(2)定义fibonacci函数计算第n项的值
}
5
2.函数说明
4.2 函数的声明、定义和调用
▪ 说明格式为:
函数返回值类型 函数名(参数表);
#include <stdio.h> float fmax(float x , float y); /*函数说明*/ void main() {
float a , b , c; scanf( “%f,%f”, &a , &b ); c = fmax(a , b); printf( “max=%f\n”, c ); }
float a , b , c; scanf( “%f,%f”, &a , &b ); c = fmax(a , b); /*函数调用*/ printf( “max=%f\n”, c ); }
float fmax(float x , float y) /*函数定义*/
{ float z; z = x > y ? x : y; return z;
(2) 如果要输出的数据超过一位,则可将该整数分为两部分:个 位上的数字和个位以前的数字。个位上的数字可以直接输出, 而个位以前的数字又可以看成一个新的整数,重复执行“反 向输出”的操作。这时,反向输出在规模上缩小了一位,但 求解的方法还是一致的。
(3) 用表达式x % 10可以分离出一个整数个位上的数字,用表达 式x / 10可以表示出个位以前的数。定义一个反向输出函数 invertLongInt,每次先用x % 10计算并输出个位上的数,然 后用x / 10(即个位以前的数)做参数调用自己,不断进行下 去,直到只剩一位数字。
return x > y ? x : y; } void main() {
float max; max = fmax(3.5 , 2.6); printf( “max=%f\n” , max); }
结果?
9
▪ 形参和实参
4.2 函数的声明、定义和调用
➢ 形式参数:定义函数时放在函数名称之后括号中的参 数,简称形参。
void main() {
float a , b; scanf( “%f,%f”, &a , &b ); swap(a,b); printf( “%f,%f\n”, a,b); }
4.2 函数的声明、定义和调用
实参a 3.5
实参b 2.6
3.5
2.6
形参x
形参y
图4-2 实参和形参数据的传递
11
▪ 函数的调用过程
23
递归函数可以写为: void invertLongInt(long x) {
if(x >=0 && x <= 9) printf("%d\n" , x);
else { printf("%d" , x % 10); invertLongInt(x / 10); }
}
4.3 函数的多级调用
24
▪ 小结: ➢ 函数分为系统函数和自定义函数。 ➢ 每个函数的都是独立定义的,如果函数定义在后、 调用在前,要对函数原型进行说明。 ➢ 除了主函数外,其他函数可以相互调用,如果A 调用B,B又调用C,称为嵌套调用,如果直接或 间接调用自己,称为递归。
第4章 模块化程序设计
北京交通大学计算机学院 赵宏
1
教学目标
▪ 理解如何用函数模块构造程序 ▪ 熟悉标准库中常见的函数 ▪ 会定义和调用函数并理解函数调用的机制 ▪ 掌握变量的作用域和存储类别 ▪ 理解并运用递归函数编写程序。
2
4.1 模块化程序设计概述 4.2 函数的声明、定义和调用 4.3 函数的多级调用 4.4 变量的作用域和存储类别 4.5 计算机随机模拟方法 4.6 编译预处理
else m = k(n - 1) * 3;
/*调用自身,n为奇数*/
return(m);
}
void main( )
{
printf("\nk(%d)=%f" , k( 4 ));
}
21
3. 递归调用举例
4.3 函数的多级调用
【例4-6】求Fibonacci数列第n项的值。Fibonacci数列以1,1 开头,以后每一项都是前两项之和。
➢ 实际参数:调用函数时括号中的参数,简称实参。