c++程序设计谭浩强第4章修订Word文档格式.docx
《c++程序设计谭浩强第4章修订Word文档格式.docx》由会员分享,可在线阅读,更多相关《c++程序设计谭浩强第4章修订Word文档格式.docx(43页珍藏版)》请在冰豆网上搜索。
{p_star();
message();
p_star();
4.2.2有参函数定义的一般形式
函数值类型函数名(类型名形参1,类型名形参2,…)//函数首部
{
说明部分//函数体
执行部分
例4.2编写程序计算组合数:
C(n,k)=n!
/(k!
(n-k)!
)
问题分析:
由于在该程序中多次遇到阶乘问题,因此可将阶乘的求解设计成函数,以便多次调用,从而避免了重复性编程。
intfac(intm)
{inti,s=1;
for(i=1;
i<
=m;
i++)
s*=i;
return(s);
intfac(intm)//自定义函数
for(i=1;
return(s);
intmain()
{intn,k,c;
Pleaseinput(n,k):
//输入n,k的值
cin>
>
n>
k;
c=fac(n)/(fac(k)*fac(n-k));
//3次调用函数fac,求n!
,k!
,(n-k)!
”C(n,k)=”<
c<
endl;
}
4.2.3说明
函数首部:
是函数的接口部分。
其中:
函数值类型规定了函数返回值的数据类型;
函数名是函数的标志,要符合标识符命名规则且在同一程序中,函数名必须唯一。
此外,若在函数首部省略了函数返回值的类型,C则默认为函数值类型为int型。
形参数列表:
为外界(即主调函数)要传给本函数的数据。
函数体:
由声明部分和执行部分构成。
其中声明部分是对函数内使用的变量类型等进行定义和声明;
执行部分是实现函数功能的语句序列。
4.3函数参数和函数的值(P91)
4.3.1形参与实参的概念
函数定义中的参数称为形参,函数调用中的参数称为实参。
其作用是:
实现函数之间的数据传递。
例4.3利用自定义函数求两个整数中的较大数。
(P91例4.2)
intmax(intx,inty)//指定形参x,y
{intz;
z=x>
y?
x:
y;
return(z);
{inta,b,c;
pleaseentertwointegernumbers:
a>
b;
c=max(a,b);
//a,b为实参
max="
return0;
1.关于形参的说明
①形参在函数定义中并不占用内存空间,他们只是表示上的一种形式,仅当该函数被调用时,才给形参分配存储单元。
此时形参的值为主调函数中对应实参传递给的数据。
被调函数执行完后,又将释放形参所占用的存储单元;
②形参在函数定义中必须进行类型说明;
注:
形参仅是形式上的,取什么名字于程序的结果毫无关系。
2.关于实参的说明
①实参是传值的。
实参可以是常量、变量或表达式,但在函数调用时,他必是可求的值。
在执行函数调用时,先计算每个实参的值,然后把值传给对应的形参;
②实参在类型、个数、顺序上要与形参一一对应,否则会产生意想不到的结果;
③函数调用时发生的数据传递是单向的。
即每次调用时,实参的值就会传递给形参,但形参的变化不会影响到实参。
例4.4交换两个变量的值。
原本希望通过调用swap()函数来交换变量x和y的值,但形参a和b的变化并没有影响到实参x和y。
为什么?
voidswap(inta,intb)
{inttmp;
a=”<
a<
”,b="
b<
tmp=a;
a=b;
b=tmp;
{intx=20,y=-40;
”x=”<
x<
”,y=”<
y<
swap(x,y);
return0;
4.3.2函数的返回值(P93)
函数是完成特定功能的程序段,主调函数通过函数调用完成一定的功能,有时调用函数的目的就是为了得到一个计算结果,这就是函数的返回值。
return语句的一般形式:
return[(表达式)]
或
return[()]
说明:
①return语句有两个作用:
一是退出被调函数立即将控制权交给主调函数;
二是回送一个函数值,即函数的返回值是通过被调函数中的return语句得到的。
②return语句的执行过程是:
先计算表达式的值,再将计算结果返给主调函数。
如例4.4中的max函数可改为:
intmax(intx,inty)//指定形参x,y
{
return(x>
y);
③return语句中表达式的类型应与函数定义中的函数类型相容。
若函数定义中没有指名函数类型,则系统自动处理为整型。
若return语句中表达式的类型与函数类型不一致,则系统自动将表达式的值转换成函数类型后再传给主调函数,即函数类型决定了返回值的类型。
④若函数不带返回值,此时,用void来定义函数类型,以明确表明该函数是无返回值的,从而可提高程序的正确性。
4.4函数的调用(P94)
4.4.1函数调用的一般形式
函数调用的一般形式为:
函数名(实参表)
函数名()
函数调用时的语法要求
(1)调用函数时,函数名必须与所调用的函数名字保持一致;
(2)实参的个数及类型要与形参的个数及类型一致;
(3)在C++中,函数可以直接或间接的调用自己(即递归调用)
C规定,函数必须先定义,后调用(函数返回值为int与char类型的函数除外);
4.4.2函数调用的方式
1.函数表达式
例如:
有如下一个名为add的函数:
doubleadd(doublea,doubleb)
{doubles;
s=a+b;
returns;
则可有以下调用方式:
y=add(2,4);
//表达式调用
for(y=0,i=1;
=5;
i++)
y=add(y,i);
//表达式调用
2.函数语句
例如4.4中的:
swap(x,y);
//独立语句调用
3.函数参数
例4.5 对例4.3进一步修改为:
求三个整数中的最大数。
{intz;
return(z);
{inta,b,c;
pleaseinputthreenumbera,b,c:
cin>
b>
c;
”Maxis:
max(a,max(b,c))<
无论是有参函数调用,还是无参函数调用,括号()不能省略;
4.4.3函数的调用过程
首先将主调函数中实参的值传递给被调函数中对应的形参(如果是有参函数)然后将控制权交给被调函数,再执行被调函数的函数体,当被调函数执行完毕后或者带给主调函数一个返回值或者不带返回值,最后将控制权重新交给主调函数。
4.4.4函数的声明和函数原型
一、函数的声明(P94)
1、函数声明的意义
函数声明的目的是为了使编译系统在编译阶段对函数的调用进行合法性检查。
判断形参与实参的类型及个数是否一致。
若没有声明函数就直接使用,那么,只有在运行时才会发现实参与形参不匹配的错误,就需要重新调试程序从而加大了工作量。
2、函数声明的方式
函数类型函数名(参数类型1,参数类型2,…)
函数类型函数名(参数类型1,参数名1,参数类型2,参数名2…)
例4.6对被调函数作声明(P95)
{floatadd(floatx,floaty);
//函数声明
floata,b,c;
pleaseentera,b:
c=add(a,b);
cout<
sum="
return0;
floatadd(floatx,floaty)
{floatz;
z=x+y;
return(z);
注1:
当被调函数的定义出现在主调函数之前可省略对函数的声明
注2:
函数的定义与函数的声明的区别
二、函数的原型
在函数声明中只给出函数的类型,而不给出函数的形参名。
floatadd(float,float);
注:
函数的原型一定要与函数的定义(即函数首部)保持一致
阅读P96~97
4.5函数的嵌套调用(P97)
在一个函数的调用过程中又调用了其他函数
例4.7计算:
1!
+2!
+3!
+……+10!
longfac(intp)
{longt=1,j;
for(j=1;
j<
=p;
j++)
t=t*j;
returnt;
longsum(intn)
{longk,s=0;
for(k=1;
k<
=n;
k++)
s=s+fac(k);
retuens;
{longadd;
add=sum(10);
“add=”<
add<
例4.8编写函数isprime(inta)用来判断自变量a是否为素数,若是素数,函数返回1,否则返回0。
#include<
math.h>
intisprime(int);
//函数声明
{intx;
enteraintegernumber:
"
x;
if(isprime(x))
”isprime"
else
”isnotprime"
intisprime(inta)
{inti;
for(i=2;
=sqrt((double)a);
if(a%i==0)return0;
return1;
例4.9编写函数,验证任意偶数为两个素数之和并输出这两个素数。
//函数声明
voideven(int);
{inta;
enteraevennumber:
a;
if(a%2==0)
even(a);
”isn'
tevennumber"
isprime(inta)
for(i=2;
=sqrt((double)a);
i++)
if(a%i==0)return0;
return1;
voideven(intx)
=x/2;
if(isprime(i)&
&
isprime(x-i))
{cout<
x<
=”<
i<
”+”<
x-i<
break;
例4.10编写函数sum(intn)用以求:
∑f(x)(x=0~n),和数作为函数值返回。
这里:
f(x)=x2+1
intsum(int);
intf(int);
{inta,b;
b=sum(a);
”,sum="
f(intx)
{returnx*x+1;
sum(intn)
{intx,s=0;
for(x=0;
x++)
s+=f(x);
4.6函数的递归调用(P99)
一、函数递归调用的定义
一个函数在他的函数体内直接或间接地调用他自身,称为递归调用。
直接调用间接调用
二、一个问题可以采用递归方法解决的必要条件为:
(1)可以把要解决的问题转化为一个新的问题,而这个新的问题的解法仍与原来的解法相同,只是所处理的对象有规律地递增或递减;
(2)可以应用这个转化过程使问题得到解决;
(3)必定要有一个明确的结束递归的条件。
三、递归调用的过程
从设计的角度考虑,递归算法涉及到两个问题:
一是递归的公式,一是递归的终止条件。
递归过程可以表述为:
if(递归终结条件)
return(终结条件下的值)
else
return(递归公式)
例4.11用递归法计算n!
,用公式表示为:
(P102例4.6)
n!
=n×
(n-1)(n≥2)
=1(n=0,1)
longpower(int);
{intn;
longy;
pleaseinputaninteger:
n;
y=power(n);
n<
!
="
longpower(intn)
{longf;
if(n<
0)
{cout<
0,dataerror!
f=-1;
}
elseif(n==0||n==1)f=1;
elsef=power(n-1)*n;
returnf;
说明
①每次嵌套调用的函数都是该函数本身;
②嵌套调用不会无限制进行下去,总会在某种条件下结束;
③每次调用时,本次的函数体并没有执行完毕。
故必须依靠系统提供一个特殊部件(堆栈)存放未完成的操作,以保证当递归调用结束时不会丢失操作。
④在递归调用时将递归过程中未执行的操作依次从堆栈栈底开始存入(简称压栈),当递归结束时再依存放时的相反顺序将它们从堆栈栈顶弹出(简称出栈),系统用堆栈指针指示应该存入和取出数据的位置。
堆栈:
一段先进后出的内存区域。
例4.12用递归函数实现反向输出输入字符串。
{voidreverse();
//函数声明
reverse();
voidreverse()
{charch;
ch=getchar();
if(ch=='
\n'
putchar(ch);
else
{reverse();
}
*4.7内置函数(P103)
一、内置函数的定义及引入的目的
inline返回值类型函数名称(参数类型参数名称。
。
函数体
引入内联函数的目的是:
为了提高程序的运行效率。
例4.13内置函数的使用
inlinedoublecircle(doubler)
{return3.1416*r*r;
{for(inti=1;
=3;
r="
area="
circle(i)<
二、几点说明
①内置函数必须先定义(不是声明),而后再使用;
②内置函数体内一般不能有循环语句和开关语句;
③在类结构中所有在类说明体内定义的函数都是内置函数;
④使用内置函数是一种用空间换时间的措施,一般适用于较短的函数。
*4.8函数的重载(P104)
一、函数重载的含义
C++允许创建多个名称相同的函数,称为函数重载。
这些同名函数的参数表必须有所区别,这种区别可以是参数类型,也可以是参数个数或两方面兼有。
例4.14参数类型不同的重载函数
求3个数中的最大数(分别考虑整数、实数、长整数的情况)
intmax(inta,intb,intc)
if(b>
a)a=b;
if(c>
a)a=c;
returna;
floatmax(floata,floatb,floatc)
longmax(longa,longb,longc)
floatd,e,f;
longg,h,i;
d>
e>
f;
g>
h>
i;
intm;
m=max(a,b,c);
max-i="
m<
floatn;
n=max(d,e,f);
max-f="
longp;
p=max(g,h,i);
max-l="
p<
例4.15参数个数不同的重载函数
intadd(intx,inty)
{returnx+y;
intadd(intx,inty,intz)
{returnx+y+z;
{inta=3,b=4,c=5;
'
+'
='
add(a,b)<
add(a,b,c)<
二、说明
(1)返回类型不在参数匹配检查之列;
(2)在函数调用时,如果给出的实参和形参不相符,C++的编译器将会自动做类型转换;
(不提倡)
(3)让重载执行不同的功能,是不好的编程风格。
同名函数应具有相同的功能。
如果定义一个abs()函数而返回的却是一个数的平方根,则该程序的可读性将受到破坏。
*4.9函数的模板(P107)
一、模板的概念
模板是C++语言中代码重用的一种实现方法。
使用模板可以实现用同一代码实现一组相关函数或一组相关类。
由于C++的程序结构主要是由函数和类构成的,因此,模板也具有两种不同的形式:
函数模板和类模板。
根据模板用户可构造模板函数和模板类。
二、函数模板的说明
所谓函数模板是指:
建立一个通用的函数,其函数类型和函数形参类型不具体指定。
用一个虚拟的类型来代表。
函数模板说明的一般形式:
template<
typename类型参数>
返回类型函数名(模板形参表)//通用函数定义
函数体;
或:
class类型参数>
返回类型函数名(模板形参表)//通用函数定义
例4.16见P107例4.10
typenameT>
//模板声明
Tmax(Ta,Tb,Tc)//定义通用函数
{if(b>
{inta1=4,a2=5,a3=8,a;
floatb1=2.3,b2=4.5,b3=1.1,b;
longc1=234561,c2=897766,c3=7877777,c;
a=max(a1,a2,a3);
b=max(b1,b2,b3);
c=max(c1,c2,c3);
cout