高级语言程序设计(第5章) 第五章 函数调用 5.1 void 函数 5.2 传值调用与传引用调用 5.3 使用过程抽象 5.4 测试和调试函数 5.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); pants_size=clothing_size(weight,age+10); … 函数定义 } double.

Download Report

Transcript 高级语言程序设计(第5章) 第五章 函数调用 5.1 void 函数 5.2 传值调用与传引用调用 5.3 使用过程抽象 5.4 测试和调试函数 5.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); pants_size=clothing_size(weight,age+10); … 函数定义 } double.

高级语言程序设计(第5章)
第五章 函数调用
5.1 void 函数
5.2 传值调用与传引用调用
5.3 使用过程抽象
5.4 测试和调试函数
5.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);
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);}
高级语言程序设计(第5章)
返回一个值的函数特征:
1. 它是完成子任务的一个小程序;
2. 传给这个小程序的实参是它的输入;它的传值调用形
参是局部于函数的变量(局部变量),它接收主调程
序传送的实参的值。
3. 它生成一个值作为它惟一的结果,这个返回值相当于
这个小程序的输出。
总之,这样的函数总是返回一个值,它是黑盒函数
定义的理想模式。
事实上,一个子任务有三种情况:
(1)产生一个值;
(2)不产生值或其它子任务不需要它产生的值;
(3)产生多个值;
不返回值的函数称为void 函数
高级语言程序设计(第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;
}
高级语言程序设计(第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语句
}
高级语言程序设计(第5章)
5.1.2 void函数编程实例
例 5_1
将华氏温度转换为摄氏温度
转换公式为:C=(5/9)(F-32)
华伦海托(1714),德国物理学家,制定了华氏温度,他发
现水银气压表的指示刻度会随着温度的变化而变化 。
摄尔西乌斯(1742),瑞典天文学家。依据冰水混合(0oC
)和与水的沸点(100oC)制定了摄氏温度。
如:104oF=40oC
高级语言程序设计(第5章)
任务分解
将一个总任务分解成四个子任务,每个子任务都
有一个独立的函数来完成:
将华氏温度转换为摄氏温度
屏幕初
始化
主函数完成
数据的输入
温度转
换函数
温度输
出函数
高级语言程序设计(第5章)
函数的完整声明
四个子任务由四个函数来实现,我们首先写出这三个函
数的完整声明(主函数不用声明):
void initialize_screen();
//将当前输出与上个程序分开或清屏;
double celsuis(double fahrenheit);
//前条件:形参fahrenheit是华氏温度。
//后条件:将华氏温度转换为摄氏温度;
void show_results(double f_degree,double c_degree);
//显示华氏温度及相应的摄氏温度。
高级语言程序设计(第5章)
函数的实现
这个return是
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);
这个return
cout<<f_degree<<"华氏温度等价于";
是可选的,并
cout<<c_degree<<"摄氏温度。"<<endl;
可多次出现
return;
}
高级语言程序设计(第5章)
void 函数中的 return语句
void show_results(double f_degree,double c_degree)
{
if(c_degree>0)
这个return
{
是可选的,
cout<<f_degree<<"华氏温度等价于" 并可多次
<<c_degree<<"摄氏温度。"<<endl; 出现,它标
志着函数
return;
运行的终
}
止。
cout<<“数据错误!"<<endl;
return;
}
高级语言程序设计(第5章)
在主函数中调用自定义函数
int main()
Void 函数的调用
{
是一个独立的可
执行语句
double f,c;
initialize_screen();
cout<<"我们将华氏温度转换为摄氏温度!"<<endl;
cout<<"请输入华氏温度:";
cin>>f;
c=celsuis(f);
show_results(f,c);
return 0;
}
高级语言程序设计(第5章)
关于return语句
return语句(称为返回语句)具有如下三种使用格式:
return;
return <表达式>;
return ( <表达式> );
第一种格式的return用于立即从被调函数中返回, 当函数
类型为void时,应使用这种格式的返回语句。
当函数类型为非void型时,应使用第二或第三种格式的
return语句,此两种格式的语句效果完全相同(可将第二种
格式看成是第三种格式的省略形式),系统此时都将计算出
表达式的值,并“携带”该值立即从被调函数中返回。
高级语言程序设计(第5章)
5.2 值调用与引用调用
一个子任务的功能有三种情况:
 (1)产生一个值;
 (2)产生多个值;
(3)不产生值或其它子任务不需要它产生的值
,但需要完成一项任务(如显示、存储文件等)
。
引用形参能将函数产生的多个值返回
高级语言程序设计(第5章)
5.2.1 引用参数的概念
若参数表中某参数的类型被指定为“<类型> &”
,则称该参数为引用参数,否则为赋值参数。如:
void show_results(double f_degree,double
c_degree);
//它所用的两个参数均为赋值参数。
void swap(int& a, int& b);
//它所用的两个参数均为引用参数。
语法要求:调用函数时,引用参数对应的实参
必须是指定类型的变量。
高级语言程序设计(第5章)
对函数进行调用的执行过程(步骤):
(1) 将对应实参表达式的值赋给赋值形参(若参数为赋
值参数的话);
(2) 用实参变量替换相应的形参(若参数为引用参数的
话);
(3) 按各形参的“当前值”(或已被“赋值”,或已被
“换名”)去执行一遍函数体并返回调用处。
f(1,2)___void f(int x,int y)
f(a,b)___void f(int &x,int &y)
高级语言程序设计(第5章)
结论:
(1) 通过赋值参数来传值的方式是一种“单
向传值”方式,它只可向被调函数的形参“传入”
值,而不可通过该形参“传出”值。
即函数中对形参的各种修改不改变实参。
(2) 通过引用参数来传值的方式是一种“双
向传值”方式,它不仅可向被调函数的形参“传入”
值,而且还可通过该形参“传出”值。
即函数中对形参的任何修改都直接改变了实参。
高级语言程序设计(第5章)
5.2.2 编程实例:swap函数
例5_2 交换内存中两个变量之值。
函数描述即函数声明:
void swap (int& a,int& b);
//交换形参a与b的值
交换前:
交换后:
a
3
b
4
a
b
3
4
高级语言程序设计(第5章)
函数算法实现:
void swap(int &x,int &y)//引用参数
//void swap(int a ,int b )//值参
{
int t=a;
a=b;
b=t;
}
高级语言程序设计(第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;
}
高级语言程序设计(第5章)
//函数体
void swap(int &x,int &y)//引用参数
//void swap(int a ,int b )//值参
{ int t=a;a=b;b=t; }
a
3
b
4
a
4
b
3
按值传送
a
3
b
4
实参
x
y
形参
引用调用
高级语言程序设计(第5章)
思考
1.在什么情况下选用赋值参数?在什么情况下选
用引用参数?
2.比较赋值参数与引用参数各自的优缺点
赋值参数功能上的缺陷
引用参数的副作用
高级语言程序设计(第5章)
5.3 使用过程抽象
5.3.1 函数的嵌套调用与递归调用
5.3.2 前条件与后条件
5.3.3 案例分析:超市定价系统
高级语言程序设计(第5章)
5.3.1 函数的嵌套调用
1.函数嵌套的概念
一个函数体中又包含了一个或多个函数的调用,称为
函数的嵌套。
main()
func1(x)
func2(x)
高级语言程序设计(第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;
}
高级语言程序设计(第5章)
函数嵌套调用关系
main()
order(x)
swap(x)
高级语言程序设计(第5章)
3. 函数的递归调用
一个函数体中又调用了它自已,称为函数的递归调用。
main()
function(x)
function(x)
高级语言程序设计(第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”
高级语言程序设计(第5章)
5.3.2 前条件与后条件
为函数声明写注释信息时,可将说明信息分为两种。
前条件:
指出函数调用时要满足的条件,称为前条件;
后条件:
对函数调用结果的描述,即在满足前条件的前提下,指
出函数执行之后将满足什么条件(得到什么结果),称为后
条件。
具体的说就是对于要返回一个值的函数,后条件是对该
返回值的描述;对于产生多个返回值的函数后条件是对这批
值的描述,实际是对引用参数的修改描述。
高级语言程序设计(第5章)
如:
void swap (int& a,int& b);
//前条件:a,b已被赋值
//后条件:交换a与b的值
double celsuis(double fahrenheit);
//前条件:形参fahrenheit是华氏温度。
//后条件:将华氏温度转换后的摄氏温度;
高级语言程序设计(第5章)
5.3.3 案例分析:超市定价系统
1.问题定义
Quick_shop连锁超市的定价策略:
预计当7天之内售出时(<=7):
商品零售价=批发价+批发价*5%
预计当7天之后才能售出时(>=8):
商品零售价=批发价+批发价*10%
 输入:商品批发价(进价)、预计售出的天数
 输出:商品零售价
高级语言程序设计(第5章)
2.问题分析
将这个问题分成三个子任务:
(1)输入数据;
(2)计算商品零售价;
(3)输出结果。
三个任务由三个函数来完成:
1)输入函数
void get_input(double &cost,int &turnover);
//前条件:用户准备好从键盘输入二个正确数据至内存
//后条件:cost设为一商品的批发价,rurnover为商品预
计售出的天数
高级语言程序设计(第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的值
高级语言程序设计(第5章)
3.算法设计
//返回商品的零售价
double price(double &cost,int &turnover)
{
if(turnover>THRESHOLD)
return cost+cost*LOW_MARKUP;
else
return cost+cost*HIGH_MARKUP;
}
高级语言程序设计(第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);
}
高级语言程序设计(第5章)
5.程序测试
(1)输入的种类
低涨幅:5%
高涨幅:10%
(2)边界值测试
预计售出天数
THRESHOLD=7
相差1错误:
THRESHOLD=6
THRESHOLD=8
高级语言程序设计(第5章)
ERROR1:">"--"<";
高级语言程序设计(第5章)
高级语言程序设计(第5章)
ERROR2;"<"__"<="
高级语言程序设计(第5章)
5.4 测试和调试函数
1.驱动程序测试法
写一个特殊的程序,以尽可能简单的方法
为函数获取参数值,然后执行函数,并显
示结果。
高级语言程序设计(第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”
高级语言程序设计(第5章)
2. stub(占位函数)测试法
在测试一个函数A时,要用到另一个还没有被测试
的函数B,用B的简化版替代B,则称此B的简化版为
stub.
高级语言程序设计(第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”
高级语言程序设计(第5章)
5.5 常规调试技术
1. 常见错误
(1)未初始化的变量;
(2)相差1错误;//<——<==
(3)超过数据边界;//35!
(4)自动类型转换;//5/9,重载函数形参
(5)该用“==”的地方用了 “=”。//逻辑表达式中
2.定位错误
(1)利用cout语句设置跟踪标志
(2)利用调试器(debugger)设置断点。
高级语言程序设计(第5章)
3.利用调试器调试程序
(1)利用调试器(debugger)设置断点
1)设置固定断点
鼠标左单击某个有效语句行首,单击【F9】键,该行
左端出现圆点标记,说明该行设置了断点,调试到该行就
会临时中断,单击【F5】继续调试.
2) 设置与条件相关的断点
使用【edit】菜单下的【Breakpoint】命令可以设置与
某个条件有关的断点。
(2)调试
执行调试命令,单击【F5】键即可,继续执行,仍单击
【F5】键。
高级语言程序设计(第5章)
5.6 案例分析:长度的换算
1.问题定义
5_8 写一个程序,要求它读入一个用成米和厘
米表示的长度,换算英尺和英寸。或它读入一
个用英尺和英寸成表示的长度,换算米和厘米,
采用那种换算由用户选择。
1英尺=0.3048米,1米=100厘米,
1英尺=12英寸。
高级语言程序设计(第5章)
长度的换算的功能目标
高级语言程序设计(第5章)
2.问题分析
将这个问题分成四个层次的子任务(共11个小任务)
main()
menu_select()
Britesh_metric()
input_British(…)
British_metric(…)
give_results(…)
introduction()
metric_British()
input_British(…)
metric_British (…)
give_results(…)
高级语言程序设计(第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设为一个长度的英尺数和英寸数
高级语言程序设计(第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的值
高级语言程序设计(第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');
高级语言程序设计(第5章)
if(select=='1')
{
cout<<"将一个英制长度换算成公制长度\n";
British_metric();
}
else
{
cout<<"将一个公制长度换算成英制长度\n";
metric_British();
}
}
高级语言程序设计(第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');
}
高级语言程序设计(第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厘米
高级语言程序设计(第5章)
5_12习题程序的结构
main()
menu_select()
menu_select_weight ()
introduction()
menu_select_length ()
Britesh_metric_weight() metric_British_weight () Britesh_metric_length metric_British_length (
input_British_weight input_British_weight
British_metric_weight metric_British_weight
output_weight
output_weight
input_British_length input_British_length
British_metric_length metric_British_length
output_weight
output_length
高级语言程序设计(第5章)
小结
函数的功能不一定仅仅是求一个数值。
一个c++函数还可以求出多个数值。
一个c++函数通常可以完成一项任务。
函数有声明、定义、调用之分。
函数有参数。
定义时的参数称为形参,调用时的参数称为实参。
根据参数的作用不同,又分为传值参数、引用参数。
设计函数时,首先要搞清楚前条件、后条件。
对设计的函数要进行科学严密的测试。
高级语言程序设计(第5章)
书面作业
1.P170自测题 6.
2.P178 自测题 7.
3.P185 自测题 13
4.P188 自测题 19,22
5.P195 编程项目 第6,7,8 小题
补充作业题:
利用递归函数计算e=1+1/1!+1/2!+…+1/n! ,其中
n为正整数。
补充选作题:
n
利用递归函数计算组合数 Cm,其中m,n为正整数。
利用递归函数求菲波那契数列的第n项(见P116
ex3_10)。
高级语言程序设计(第5章)
实验四 函数
实验类型:综合型
实验目的:
1.进一步熟悉VC++6.0集成开发环境;
2.进一步熟悉控制结构程序设计方法;
3.掌握函数的定义和调用方法;
4.掌握函数嵌套(或递归)调用的方法;
5.理解变量的作用域和生存期;
高级语言程序设计(第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)分析程序中全局常量与局部变量的作用域与生存期。