第 五 章 函数 调用

58
高高高高高高高高 ( 高 5 高 ) 第第第 第第第第 5.1 void 第第 5.2 第第第第第 第第第第 传传 5.3 第第第第第第 5.4 第第第第第第第 5.5 第第第第第第 第第

description

第 五 章 函数 调用. 5.1 void 函数 5. 2 传值调用与传引用调用 5. 3 使用过程抽象 5. 4 测试和调试函数 5.5 常规调试技术 作业. 5.1 void 函数. 函数声明. // 习题 4_10… double clothing_size(double height ,double weight,int age); // 返回用户服装(上衣)的尺码 ( 英寸 ) int main(){… blouse_size=clothing_size( height,weight,age+10); - PowerPoint PPT Presentation

Transcript of 第 五 章 函数 调用

Page 1: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

第五章 函数调用

5.1 void 函数5.2 传值调用与传引用调用5.3 使用过程抽象5.4 测试和调试函数5.5 常规调试技术作业

Page 2: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.1 void 函数// 习题 4_10…double clothing_size(double height ,double weight,int age);//返回用户服装(上衣)的尺码 (英寸 )int main(){ …

blouse_size=clothing_size( height,weight,age+10);pants_size=clothing_size(weight,age+10); …

}double clothing_size(double height ,double weight,int age){//返回用户服装(上衣)的尺码 (英寸 ) double size=weight*height/288; if(age>30) //30岁以后,每增加 10岁尺码加 1/8

size=size+(1/8.0)*(age-30)/10; return (size);}

函数调用

函数声明

函数定义

Page 3: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

返回一个值的函数特征:1. 它是完成子任务的一个小程序;2. 传给这个小程序的实参是它的输入;它的传值调用形参是局部于函数的变量(局部变量),它接收主调程序传送的实参的值。

3. 它生成一个值作为它惟一的结果,这个返回值相当于这个小程序的输出。

总之,这样的函数总是返回一个值,它是黑盒函数定义的理想模式。事实上,一个子任务有三种情况:( 1)产生一个值;( 2)不产生值或其它子任务不需要它产生的值;( 3)产生多个值;

不返回值的函数称为 void 函数

Page 4: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.1.1 void函数的定义//已知华氏温度及相应的摄氏温度,输出这两个温度值。void show_results(double f_degree,double c_degree)

{

cout.setf(ios::fixed);

cout.setf(ios::showpoint);

cout.precision(1);

cout<<f_degree<<“华氏温度相当于 "

<<c_degree<<"摄氏温度。 "<<endl;

return;

}

Page 5: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.1.1 void函数的定义(1)声明部分:

void function_name(parameter_list);(2) 调用部分:一个独立的可执行语句

Void main(){ …

function_name(real_parameter_list);}(3) void函数定义:

void function_name(parameter_list);{

…return;//可以包含一个或多个 return语句,也可以没有return语句

}

Page 6: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.1.2 void函数编程实例

例 5_1 将华氏温度转换为摄氏温度转换公式为: C=(5/9)(F-32)

华伦海托( 1714),德国物理学家,制定了华氏温度,他 发现水银气压表的指示刻度会随着温度的变化而变化 。

摄尔西乌斯( 1742),瑞典天文学家。依据冰水混合( 0oC)和与水的沸点( 100oC)制定了摄氏温度。

如: 104oF=40oC

Page 7: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

任务分解将一个总任务分解成四个子任务,每个子任务都

有一个独立的函数来完成:

将华氏温度转换为摄氏温度

屏幕初始化

主函数完成数据的输入

温度转换函数

温度输出函数

Page 8: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

函数的完整声明四个子任务由四个函数来实现,我们首先写出这三个函

数的完整声明(主函数不用声明):void initialize_screen();

//将当前输出与上个程序分开或清屏;

double celsuis(double fahrenheit);

//前条件:形参 fahrenheit是华氏温度。//后条件:将华氏温度转换为摄氏温度 ;

void show_results(double f_degree,double c_degree);

//显示华氏温度及相应的摄氏温度。

Page 9: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

函数的实现double celsuis(double fahrenheit){

return ((5.0/9.0)*(fahrenheit-32));}void show_results(double f_degree,double c_degree){

cout.setf(ios::fixed);cout.setf(ios::showpoint);cout.precision(1);cout<<f_degree<<"华氏温度等价于 ";cout<<c_degree<<"摄氏温度。 "<<endl;return;

}

这个 return是可选的 ,并可多次出

这个 return是必须的

Page 10: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

void 函数中的 return语句void show_results(double f_degree,double

c_degree){

if(c_degree>0){cout<<f_degree<<"华氏温度等价于 "<<c_degree<<"摄氏温度。 "<<endl;return;}

cout<<“数据错误 !"<<endl;return;

}

这个 return是可选的 ,并可多次出现 , 它标志着函数运行

的终止。

Page 11: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

在主函数中调用自定义函数int main(){

double f,c;initialize_screen();cout<<"我们将华氏温度转换为摄氏温度! "<<endl;cout<<"请输入华氏温度: ";cin>>f;c=celsuis(f);show_results(f,c);return 0;

}

Void 函数的调用是一个独立的可

执行语句

Page 12: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

关于 return语句

return语句(称为返回语句)具有如下三种使用格式:return;return <表达式 >;return ( <表达式 > );

第一种格式的 return用于立即从被调函数中返回 , 当函数类型为 void时,应使用这种格式的返回语句。当函数类型为非 void型时,应使用第二或第三种格式的

return语句,此两种格式的语句效果完全相同(可将第二种格式看成是第三种格式的省略形式),系统此时都将计算

“ ”出表达式的值,并 携带 该值立即从被调函数中返回。

Page 13: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.2 值调用与引用调用

一个子任务的功能有三种情况: ( 1)产生一个值; ( 2)产生多个值;( 3)不产生值或其它子任务不需要它产生的值,但需要完成一项任务(如显示、存储文件等)。

引用形参能将函数产生的多个值返回

Page 14: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.2.1 引用参数的概念

若参数表中某参数的类型被指定为“ <类型 >

&”,则称该参数为引用参数,否则为赋值参数。如:void show_results(double f_degree,double c_degree);

//它所用的两个参数均为赋值参数。void swap(int& a, int& b);

//它所用的两个参数均为引用参数。  语法要求:调用函数时,引用参数对应的实参必须是指定类型的变量。

Page 15: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

对函数进行调用的执行过程(步骤):( 1) 将对应实参表达式的值赋给赋值形参(若参数为赋值参数的话);

( 2) 用实参变量替换相应的形参(若参数为引用参数的话);

( 3) “ ”按各形参的 当前值 (或已被“ ”赋值 ,或已被“ ”换名 )去执行一遍函数体并返回调用处。

f(1,2)___void f(int x,int y)

f(a,b)___void f(int &x,int &y)

Page 16: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

结论:

( 1 ) 通过赋值参数来传值的方式是一种“单向传值”方式,它只可向被调函数的形参“传入”值,而不可通过该形参“传出”值。

即函数中对形参的各种修改不改变实参。 ( 2 ) 通过引用参数来传值的方式是一种“双

向传值”方式,它不仅可向被调函数的形参“传入”值,而且还可通过该形参“传出”值。

即函数中对形参的任何修改都直接改变了实参。

Page 17: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.2.2 编程实例: swap函数例 5_2 交换内存中两个变量之值。函数描述即函数声明:

void swap (int& a,int& b);//交换形参 a与 b的值

a

3 4b

a

4 3b

交换后:

交换前:

Page 18: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

函数算法实现:

void swap(int &x,int &y)//引用参数//void swap(int a ,int b )//值参{

int t=a;

a=b;

b=t;

}

Page 19: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )例程编码

“(实例演示 5_2交换两个变量的值 .cpp”)

#include<iostream.h>void swap(int &,int &);//引用参数//void swap(int ,int );//值参void main(){int a=3,b=4;cout<<"交换前: a,b=";cout<<a<<" , "<<b<<endl;swap(a,b);cout<<"交换后: a,b=";cout<<a<<" , "<<b<<endl;}

Page 20: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

//函数体void swap(int &x,int &y)//引用参数//void swap(int a ,int b )//值参{ int t=a;a=b;b=t; }

a

3 4

b

a4

b

3

实参

形参

按值传送 引用调用

a

3 4

b

x y

Page 21: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

思考

1.在什么情况下选用赋值参数?在什么情况下选用引用参数?

2. 比较赋值参数与引用参数各自的优缺点

赋值参数功能上的缺陷引用参数的副作用

Page 22: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.3 使用过程抽象

5.3.1 函数的嵌套调用与递归调用5.3.2 前条件与后条件5.3.3 案例分析 :超市定价系统

Page 23: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.3.1 函数的嵌套调用

1.函数嵌套的概念一个函数体中又包含了一个或多个函数的调用,称为函数的嵌套。

main() func1(x) func2(x)

Page 24: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

2. 一个函数调用另一个函数举例

例 5_3 将变量值按从小到大的顺序排列。(见例程演示)void swap(int &x,int &y)//引用参数{

int t=x;x=y;y=t;}void order(int &a,int&b,int&c){

if(a>b)swap(a,b);if(a>c) swap(a,c);if(b>c) swap(b,c);return;

}

Page 25: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

函数嵌套调用关系

main() order(x) swap(x)

Page 26: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

3. 函数的递归调用一个函数体中又调用了它自已,称为函数的递归调用。

main() function(x) function(x)

Page 27: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

//递归函数的定义double factor(int number)

{

double f;

if(number<=1)

f=1;

else

{

f=number*factor(number-1);

cout<<f<<endl;;

}

return f;

}

“见例程 5_5递归法求 n!.cpp”

Page 28: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.3.2 前条件与后条件为函数声明写注释信息时,可将说明信息分为两种。

前条件: 指出函数调用时要满足的条件,称为前条件 ;

后条件: 对函数调用结果的描述,即在满足前条件的前提下,指出函数执行之后将满足什么条件(得到什么结果),称为后条件。 具体的说就是对于要返回一个值的函数,后条件是对该返回值的描述;对于产生多个返回值的函数后条件是对这批值的描述,实际是对引用参数的修改描述。

Page 29: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

如:void swap (int& a,int& b);

//前条件: a,b已被赋值//后条件 :交换 a与 b的值

double celsuis(double fahrenheit);

//前条件:形参 fahrenheit是华氏温度。//后条件:将华氏温度转换后的摄氏温

度 ;

Page 30: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.3.3 案例分析 :超市定价系统1.问题定义

Quick_shop连锁超市的定价策略:预计当 7天之内售出时 (<=7):

商品零售价 =批发价 +批发价 *5%

预计当 7天之后才能售出时( >=8):商品零售价 =批发价 +批发价 *10%

输入:商品批发价(进价)、预计售出的天数 输出:商品零售价

Page 31: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

2.问题分析

将这个问题分成三个子任务:( 1)输入数据;( 2)计算商品零售价;( 3)输出结果。

三个任务由三个函数来完成:

1 )输入函数void get_input(double &cost,int &turnover);

//前条件:用户准备好从键盘输入二个正确数据至内存//后条件: cost设为一商品的批发价, rurnover为商品预计售出的天数

Page 32: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

2 )计算函数double price(double &cost,int &turnover);

//前条件: cost设为一商品的批发价, rurnover为商品预计售出的天数//后条件:返回商品的零售价3 )输出函数void give_results(double cost,int turnover, double price);

//前条件: cost设为一商品的批发价,// rurnover为商品预计售出的天数// cost为商品的零售价//后条件:在屏幕上显示 cost、 turnover、 price的值

Page 33: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

3.算法设计

//返回商品的零售价double price(double &cost,int &turnover)

{

if(turnover>THRESHOLD)

return cost+cost*LOW_MARKUP;

else

return cost+cost*HIGH_MARKUP;

}

Page 34: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

4.程序编码(完整编码见例程 5_5)

void main()

{

double wholesale_cost,retail_price;

//批发价和零售价int sheft_time;//估计出售的时间introduction();

get_input(wholesale_cost,sheft_time);

retail_price=price(wholesale_cost,sheft_time);

give_results(wholesale_cost,sheft_time,retail_price);

}

Page 35: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.程序测试

(1)输入的种类低涨幅: 5%

高涨幅: 10%

(2)边界值测试预计售出天数

THRESHOLD=7

相差 1错误:THRESHOLD=6

THRESHOLD=8

Page 36: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

ERROR1:">"--"<";

Page 37: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

Page 38: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

ERROR2;"<"__"<="

Page 39: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.4 测试和调试函数

1.驱动程序测试法写一个特殊的程序,以尽可能简单的方法为函数获取参数值,然后执行函数,并显示结果。

Page 40: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

函数 get_input( )的驱动程序void main()

{ … char ans;

do {

get_input(wholesale_cost,sheft_time);

cout<<" 商品批发价: $"<<wholesale_cost<<endl;

cout<<" 商品预计售出天数: "<<sheft_time<<"天 "<<endl;

cout<<"继续吗?( y or n) "<<endl;

cin>>ans; cout<<endl;

}while(ans=='y'||ans=='Y');

}// “见例程 5_6函数的驱动程序 .cpp”

Page 41: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

2. stub(占位函数)测试法

在测试一个函数 A时,要用到另一个还没有被测试的函数 B,用 B的简化版替代 B,则称此 B的简化版为 stub.

Page 42: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

这是一个占位函数( stub)double price(double &cost,int &turnover)

{

if(turnover<=7)

return cost+cost*0.05;

else

return cost+cost*0.10;

return 23.9;

}

“见见例程 5_7测试超市定价系统 .cpp”

Page 43: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.5 常规调试技术1. 常见错误( 1)未初始化的变量;( 2)相差 1错误; //<——<==

( 3)超过数据边界; //35!

( 4)自动类型转换; //5/9,重载函数形参( 5 “)该用 ==” “的地方用了 =”。 //逻辑表达式中2.定位错误( 1)利用 cout语句设置跟踪标志( 2)利用调试器( debugger)设置断点。

Page 44: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

3.利用调试器调试程序( 1)利用调试器( debugger)设置断点

1)设置固定断点鼠标左单击某个有效语句行首,单击【 F9】键,

该行左端出现圆点标记,说明该行设置了断点,调试到该行就会临时中断,单击【 F5】继续调试 .

2 ) 设置与条件相关的断点使用【 edit】菜单下的【 Breakpoint】命令可以设

置与某个条件有关的断点。( 2)调试执行调试命令,单击【 F5】键即可,继续执行,仍单击【 F5】键。

Page 45: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.6 案例分析 :长度的换算1.问题定义

5_8 写一个程序,要求它读入一个用成米和厘米表示的长度,换算英尺和英寸。或它读入一个用英尺和英寸成表示的长度,换算米和厘米 , 采用那种换算由用户选择。

1 英尺 =0.3048 米, 1米 =100 厘米,1 英尺 =12 英寸。

Page 46: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

长度的换算的功能目标

Page 47: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

2.问题分析将这个问题分成四个层次的子任务 (共11个小任务 )

main()

menu_select()

Britesh_metric() metric_British()

input_British(…)British_metric(…) give_results(…)

input_British(…)metric_British (…) give_results(…)

introduction()

Page 48: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

//函数声明部分void introduction();//本系统的说明void menu_select();//后条件:根据用户的选择,执行相应的换算

void British_metric();//执行英制到公制的转换过程void metric_British();//执行英制到公制的转换过程

void input_metric(double &meter,double &centimeter);//前条件:用户准备好从键盘输入二个正确数据至内存//后条件:meter和 centimetetr为一个长度的米数和厘米数

void input_British(double &food,double &inch);//前条件:用户准备好从键盘输入二个正确数据至内存//后条件: food和 inch设为一个长度的英尺数和英寸数

Page 49: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

void British_metric(double food,double inch,double &meter,double &centimeter);

//前条件: food和 inch为给定的一个长度的英尺数和英寸数//后条件: meter和 centimetetr为返回的一个长度的米数和厘米数

void metric_British(double meter,double centimeter,double&food,double&inch);

//前条件:meter和 centimetetr为给定的一个长度的米数和厘米数//后条件: food和 inch为返回的一个长度的英尺数和英寸数

void give_results(double food,double inch,double meter,double centimeter);

//前条件: food、 inch、meter、 centimeter分别为给定的一个长度的英尺数、英寸数、米数和厘米数

//后条件:在屏幕上显示 food、 inch、meter、 centimeter的值

Page 50: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

3.算法设计

void menu_select(){

char select; do {

cout<<"---------------------------------------\n";cout<<"\t1--将一个英制长度换算成公制长度 \n";cout<<"\t2--将一个公制长度换算成英制长度 \n";cout<<"---------------------------------------\n";cout<<"请选择: ";cin>>select;

}while(select!='1'&&select!='2');

Page 51: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

if(select=='1') {

cout<<"将一个英制长度换算成公制长度 \n";British_metric();

} else {

cout<<"将一个公制长度换算成英制长度 \n";metric_British();

}}

Page 52: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

4.程序编码(完整编码见习题 5_8)void main()

{

system("color f0");

char ans;

introduction();

do

{

menu_select();

cout<<"继续吗?( y or n) ";

cin>>ans;

}while(ans=='y'||ans=='Y');

}

Page 53: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5.程序测试

程序测试输入下述几组数据,写出程序执行结果0 米 0 厘米—— 0 英尺 0 英寸0 米 2.54 厘米—— 0 英尺 1 英寸1 米 0 厘米—— 3 英尺 3 英寸30米 48 厘米—— 99 英尺 11 英寸

0 英尺 0 英寸—— 0 米 0 厘米1 英尺 0 英寸—— 0 米 30 厘米0 英尺 12 英寸—— 0 米 30 厘米6 英尺 9 英寸—— 2 米 4 厘米100 英尺 0——30米 48 厘米

Page 54: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

5_12习题程序的结构

Britesh_metric_weight() metric_British_weight ()

input_British_weightBritish_metric_weight output_weight

input_British_weightmetric_British_weight output_weight

Britesh_metric_length metric_British_length ()

input_British_lengthBritish_metric_length output_length

input_British_lengthmetric_British_length output_weight

main()

menu_select() introduction()

menu_select_weight () menu_select_length ()

Page 55: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

小结函数的功能不一定仅仅是求一个数值。一个 c++函数还可以求出多个数值。一个 c++函数通常可以完成一项任务。函数有声明、定义、调用之分。函数有参数。定义时的参数称为形参,调用时的参数称为实参。根据参数的作用不同,又分为传值参数、引用参数。设计函数时,首先要搞清楚前条件、后条件。对设计的函数要进行科学严密的测试。

Page 56: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

书面作业1.P170 自测题 6.2.P178 自测题 7.3.P185 自测题 134.P188 自测题 19,225.P195 编程项目 第 6,7,8 小题补充作业题:利用递归函数计算 e=1+1/1!+1/2!+…+1/n! ,其中 n为正整数。

补充选作题: 利用递归函数计算组合数 ,其中m,n为正整数。

利用递归函数求菲波那契数列的第 n项(见 P116 ex3_10)。

Cmn

Page 57: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

实验四 函数实验类型 :综合型实验目的:1.进一步熟悉 VC++6.0集成开发环境;2.进一步熟悉控制结构程序设计方法;3.掌握函数的定义和调用方法;4.掌握函数嵌套(或递归)调用的方法;5.理解变量的作用域和生存期;

Page 58: 第 五 章  函数 调用

高级语言程序设计 (第 5章 )

实验内容:1.编制程序,利用递归函数计算 e=1+1/1!+1/2!+…+1/n! 其中 n为正整数。分别输入 n=0、 1、 10、 170、 171,测试程序,写出对应的每个输入值的程序的运行结果,并与理论值进行比较。

2. “ ”参考例程 超市定价系统 ,假设函数 get_input和 give_output都已通过测试, price函数还没有测试,试写出利用 stub方法测试函数 introduction的程序源代码。

( 1)写出测试运行结果;( 2)分析程序中全局常量与局部变量的作用域与生存期。