土木-课件ch04函数_第1页
土木-课件ch04函数_第2页
土木-课件ch04函数_第3页
土木-课件ch04函数_第4页
土木-课件ch04函数_第5页
免费预览已结束,剩余119页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第七章函数7.1函数概述7.2函数的定义和调用7.3函数调用中的参数传递7.4函数的嵌套调用和递归调用7.5函数的返回值为指针7.6

函数的作用域和

类别7.7

函数和外部函数结构化程序设计的一个重要特点:模块化设计,即用一个函数表示

一个模块,完成若干特定的功能。函数是构成C++程序的基本构件。C++的程序是由一个主函数和≥0个其它函数组成。编译以源程序文件为单位,不以函数为单位。7.1

函数概述7.1

函数概述不管main函数(主函数)出现在程序中的哪个位置,

C++程序的执行都以main函数开始,随着main函数的

结束而结束。所有的函数独立定义,main函数可以调用其他任意函数,其他函数之间可以互相调用,但是任何其他函数都不能调用main函数。函数体中使用其它函数函数的分类库函数:由C++编译系统提供,供用户直接使用用户自定义函数:根据实际需要,由程序员自己编写,实现特定功能有参函数:函数带有参数(有自变量)例如sqrt(x);无参函数:函数没有参数例如getchar();有返回值函数:函数被调用以后返回一个值例如getchar();sin(x);无返回值函数:函数被调用以后没有返回值例:函数调用的简单例子。#include

……void

myprint(){ inti=0;for(i=1;i<=18;i++)cout<<"*";cout<<“\n”;}void

myprint_n(int

n){ inti

=0;for(i=1;i<=n;i++)cout<<"*";cout<<"\n";}/*

调用一次输出一行固定个数的“*”(18颗)

*//*

调用一次输出一行6颗“*”*//*

调用一次输出一行12颗“*”*//*

调用一次输出一行固定个数的“*”(18颗)

*/intmain(){myprint();myprint_n(6);myprint_n(12);myprint();return

0;}自定义函数,无参数,无返回值自定义函数,有参数,无返回值调用后返回调用的地方继续往下执行例:从键盘输入x和y的值,计算xy的值(设y为整型量)。算法一:调用C++中的库函数pow,计算xy的值。#include<iostream>#include

<cmath>/*

pow函数的原型在cmath中

,所以应加此行

*/using

namespace

std;int

main(){double

x

=

0,

z

=0;int

y

=0;cout<<"Input

data:

";cin>>x>>y;z=pow(x,y);

/*

调用库函数pow计算xy的值*/cout<<x<<endl<<y<<endl<<z<<endl;return

0;}库函数,有参数,有返回值算法二:自定义函数mypow,计算xy的值。#include

……/*

自定义函数mypow开始*/double

mypow(double

x,

int

y){int

i

=

0;double

z

=

1.0;for(i=1;

i<=y;

i++)z

=

z

*

x;return

z;}

/*

自定义函数mypow结束*/int

main(

){double

x

= 0,

z

=0;int

y

=

0;cout<<"Input

data:

";cin>>x>>y;z

=

mypow(x,

y);/*

主函数*//*

调用自定义函数mypow

*/cout<<x<<endl<<y<<endl<<z<<endl;return

0;}自定义函数,有参数,有返回值引入函数的目的1.增强可读性,使主函数尽可能短,把功能实现放到子函数里,主函数只要调用子函数即可。2.模块化设计。复杂的程序,先写主函数,把每个功能用一个模块(子函数)实现,可以交由多个人同时编写。3.加强程序的可移植性,避免重复编写。需要实现某个功能,只要接口的要求一样,可以直接使用已有的模块(子函数)。注意:实参与形参的类型必须一致(字符型与整型通用);形参为变量名时,对应实参应为表达式,调用函数时把实参值单向传递给形参;形参和实参

表示未具体给定的量,不赋值1、定义函数时、函数名后面括号中的变量名、数组名等称为形式参数,简称形参。2、调用函数时、函数名后面括号中的变量名、数组名等称为实际参数,简称实参。必须已赋值、其值用来传递给形参,单向传递实参形参×形参和实参x2g(x,

y)

y2x,y:形式参数函数定义时,括号中的变量称为形式参数,简称形参32

42

5g(3,4)

3,4:实际参数函数调用时,括号中的参数称为实际参数,简称实参5:函数值函数定义函数调用7.2

函数定义和调用变量定义和

部分执行语句[函数类型名]

函数名([形参及形参

表]){}注意:函数在定义后,并没有马上执行,只有当函数被调用时,程序才转到函数去执行。函数调用的格式函数名([实参列表])方括号部分可省略函数定义的格式无参函数的定义无参函数定义的格式变量定义和执行语句[函数类型名]

函数名(){部分}void

myprint(){ inti=0;for(i=1;i<=18;i++)cout<<"*";cout<<“\n”;}有参函数的定义有参函数定义的格式表)变量定义和

部分执行语句[函数类型名]

函数名(形参及形参{}double

mypow(double

x,

int

y){inti=0;double

z

=1.0;for(i=1;i<=y;i++)z=z*

x;return

z;}还没有具体值,调用时才有,相当于定义了变量x和y,可以在函数体内使用它们空函数的定义空函数定义的格式[函数类型名]{}函数名()在程序中占一个位置,等扩充函数功能的时候补充函数的返回值函数的返回值通过return语句获得,格式:return

(表达式);或者return

表达式;注意:一个函数只能返回一个确定的值。但是一个函数可以出现多条return语句,即多个出口。int

max(int

x,

int

y){if(x>y)returnx;elsereturny;}函数的返回值函数返回值的类型取决于函数的类型。int

max(float

x,

float

y)z=x;z=y;{ float

z;if(x>y)elsereturn

z;}如果一个函数没有返回值,则可以不加return语句。或者return后不跟表达式。无返回值的函数,类型为void。返回值是float型还是int型?int型!A.无参无返回值函数的定义与调用void

print_star(){cout<<"**********\n";}intmain(){int

i;for(i=5;i<10;i++)print_star();return0;}函数类型void(空类型),表示没有返回值函数名:print_star#includ

…无参数函数定义以语句方式调用函数B.有参无返回值函数的定义与调用#includ

…void

print_star(int

n){ int

k;for(k=1;k<=n;k++)

cout<<"*"cout<<"\n";}intmain(){ int

i;for(i=0;i<10;i++)print_star(10);return0;}函数类型void(空类型),表示没有返回值函数名:print_star有参数,n,为int型函数定义以语句方式调用函数函数体内不能再定义变量n实参改成i,输出是什么?C.有返回值函数的定义与调用int

max(int

x,

int

y){ int

z;if(x>y)

z=x;

elsez=y;return(z);}intmain(){ int

a,

b,

c;cin>>

a>>b;c

=

max(a,

b);cout<<"max

is"<<c;return0;}函数类型如果是

int(可以省略),函数返回值为整型函数名:max#includ

…不能写成int

x,y函数定义max函数的返回值赋给cReturn后返回值的括号可加可不加,返回值可以是表达式。#include

…int

max(int

x,

int

y){int

z;z

=x

>y

?

x

:y;return

z;}int

main(){int

a,

b,

c;cin>>

a>>b;cout<<

"

sin(max(a,b))

=

"<<sin(max(a,

b));return

0;}作为函数的参数使用式函数的调用方1.无返回值函数:把函数调用作为一条语句使用,例如前例中的print_star(10);2.有返回值函数:(1)作为表达式的一部分参与运算(作为一个值用):例如c=max(a,b);y=sin(x)*cos(x+2);(2)作为函数的实参(作为一个值用):例如sqrt(sin(x));(3)也可作为一条语句使用,但是返回值没有被保存下来:例如putchar(‘a’);函数调用的格式:函数名(实参列表)#include

<iostream>#include

<cmath>using

namespace

std;void

prime(int

m){ intj,k;k=sqrt(m);for(j=2;j<=k;j++)if(m%j==0)break;if(j>k)

cout<<m<<" is

aprielse

cout<<m<<" is

not

a

primber";mber";}int

main(){ int

n;cin>>n;prime(n);

return

0;}没有返回值函数调用作为函数语句。#include

<iostream>#include

<cmath>using

namespace

std;prime(int

m){ int

j,k,f;

k=sqrt(m);for(j=2;j<=k;j++)if(m%j==0)break;if(j>k)

f=1;else

f=0;return

f;}int

main(){ int

n;cin>>n;if(prime(n))

cout<<n<<" is

a

prielse

cout<<n<<" is

not

a

primber";mber";return

0;}有返回值,int类型,省略函数调用作为表达式。函数调用的条件1.被调函数是库函数或者已经存在的

定义函数。2.要让编译器知道这是一个函数2.1如果被调函数是库函数,要在文件开头将相关头文件包含进来(#include)2.2如果被调函数是自定义函数,一般要在调用前进行函数原型

,

的格式是函数类型名函数名(形参名及其类型表);或者函数类型名函数名(形参类型表);例如int或者intmax(intx,

int

y);max(int

,

int

);如果被调函数定义

,调用在后,那么可以不加函数原型函数原型方式1.在主调函数2.在函数的外部,一般放在所有函数定义之前#include…int

main(

){

float

add(float

x,float

y);float

a,b,c;cin>>a>>b;c=add(a,b);cout<<“sum

is

”<<c ;

return

0;}float

add

(

float

x,float

y

){float

z;z=x+y;return

z;}1)在主调函数对被调函数add的被调函数add2)如在所有函数定义之前,在函数外。例如:char

str(int

a);float

f(float

b);main(){

……

}char

str(int

a){

……

}float

f(float

b){

……

}3)对库函数的调用不需要再作

,但必须把该函数的头文件用include命令包含在源文件前部。对str函数和f函数预先作了说明4)当被调函数的函数定义出现在主调函数之前时,。在主调函数中也可以不对被调函数再作#include…float

add

(

float

x,float

y

);{float

z;z=x+y;return

z;}int

main(

){

float

a,b,c;cin>>a>>b;c=add(a,b);cout<<“sum

is

”<<c

;

return

0;}不必对被调函数作函数定义和函数的区别构成不同,作用不同函数定义是指对函数功能的确立,包括指定函数名、函数的类型、形参及其类型以及函数体等。它是一个完整的、独立的函数单位。函数

是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(例如,函数名是否正确,实参与形参的类型和个数是否一致),它不包含函数体。7.3

函数调用中的参数传递对于无参函数,形参列表和实参列表均为空,括号不能省略,例如:add()。对于有参函数,实参和形参的个数应该相等,顺序应该对应,类型一致或者赋值相容。实参可以是常量,变量或者表达式。例如函数原型int

max(int

x,inty);调用时:max(500,a+20)或者max(a[i],y[j*3])例:

#include…

int

mult(int

n){n

*=

10;return(n);}int

main(){int

number;

int

result;number

=

668;result

=

mult(number);cout<<"number

=

"<<number<<endl;cout<<"result

=

"<<result<<endl;return

0;}调用前:形参n在mult函数定义时指定,但是,mult函数未被调用时,n不占

单元。number=668,n不存在调用时:执行到函数调用语句的时候才给形参分配单元,并将实参number的值传递给形参n,形参实参占用的

空间不同。number=668,n=668单向值传递例:#include…

int

mult(int

n){n

*=10;return(n);}int

main(){int

number;int

result;number

=

668;result

=

mult(number);cout<<"number

=

"<<number<<endl;cout<<"result

=

"<<result<<endl;return

0;}调用中:函数mult在调用过程中,n的值发生变化:

n=6680,而number的值不变,还是668调用后:mult函数调用结束时,形参所占用的内存单元被实参number的值不变。number=668,n不存在void

main(

){

int x=3

,

y=7;change

(

x

,

y

);cout<<x<<“,”<<y ;

}

void

change

(

int a

,int b

)c=a

;

a=b

;

b=c

;}结果:3,737{

int c

;

实参和形参占用不同的

单元a,b交换x、y值不变a7x3b3y7单向值传递函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。实参形参x=x*5y=y*5×

×void

main(){ int

n;cout<<"input

number\n";cin>>n;s(n);cout<<"n="<<n<<endl;}int

s(int

n){ int

i;for(i=n-1;i>=1;i--)n=n+i;cout<<"n="<<n<<endl;}输入:6输出:n=21n=6in56+5=11411+4=15315+3=18218+2=20120+1=21n=6即使形参实参的变量名相同,也是不同的变量,占不同的内存单元void

main(){int

i,j;i=2;j=3;fun(i,j);}void

s(int

i,int

j){}×

×i*=10;

j*=5;怎么在被调函数里改变主调函数里的变量值?2.指针变量作为函数参数主调函数a被调函数*q实参:指针p&a形参:指针q&a例:#include…

int

main(){

void

swap(int

*pl,

int

*p2);inta,b;int

*pointer1,

*pointer2;cin>>a>>b;/*

指针变量获

量a的地址

*//*

指针变量

得变量b的地址

*/pointerl

=&a;pointer2

=&b;if(a<

b)swap(pointer1,pointer2) /*

两个指针变量作实参

*/cout<<"max=

"

<<a<<

"

,

min

=

" <<

b;return

0;}void

swap(int

*pl,

int

*p2){ int

*temp;temp=pl;p1=

p2;p2=temp;}输入:6,8↙输出:max=6,min=8改变形参指针的值,无法实现a/*

和b两个变量值的交换例:#include…

int

main(){ void

swap(int

*pl,

int*p2);inta,b;int

*pointer1,

*pointer2;cin>>a>>b;/*

指针变量

得变量a的地址

*//*指针

量获得变量b的地址

*/pointerl

=&a;pointer2

=&b;if(a<

b)swap(pointer1,point

2);

/*

两个指针变量作实参*/cout<<"max="

<<a<<

"

,

min

=

" <<

b;return

0;}void

swap(int

*pl,int

*p2) /*

指针变量pl、p2作形参*/{ int

temp;temp=*pl;*p1

=

*p2;*p2

=

temp;}输入:6,8↙输出:max=8,min=6改变形参指针指向单元的值,才能实现a

和b两个变量值的交换如果要通过函数调用得到n个要改变的值,方法:1.主调函数:设置n个变量a1,a2,…,an,分别存放

n个要改变的值,它们的指针分别为pointer1=&a1,pointer2=&a2,…pointern=&an。2.被调函数:设置n个指针变量p1,p2,…pn作为形参,函数体改变*p1,*p2,…,*pn的值。3.函数调用:主调函数以pointer1,pointer2,…pointern为实参,将a1,a2,…,an的地址传递给形参p1,p2,…pn,于是,被调函数改变*p1,*p2,…,*pn的值,实际上就是改变a1,a2,…,an的值。函数调用结束时,主调函数中的值发生了改变例、swap(int

*p1,int

*p2){int

temp;temp=*p1;*p1=*p2;*p2=temp;}int

main(){int

a,b;int

*pointer_1,*pointer_2;cin>>a>>b;pointer_1=&a;pointer_2=&b;if(a<b)

swap(pointer_1,pointer_2);cout<<a<<",

"<<b);

return

0;}实参实参输入:5,9输出:9,

5例:

下列程序的输出结果,分析指针作函数参数的特点。#include

…void

func(int,int,int

*);void

main(){int

a=11,b=99,c;func(a,b,&a);func(a,b,&b);func(a,b,&c);/*

func函数

*//*

第一次调用func函数*//*第二次调用func函数*//*

第三次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;}void

func(int

x,int

y,int

*z){*z

=y

-

x;}a=88,b=11,c=-77#include

…void

func(int,int,int

*);void

main(){int

a=11,b=99,c=8;cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;func(a,b,&a); /*

第一次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;func(a,b,&b); /*

第二次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;func(a,b,&c); /*

第三次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;}void

func(int

x,int

y,int

*z){*z=y-x;}a=11,b=99,c=8a=88,b=99,c=8a=88,b=11,c=8a=88,b=11,c=-77#include

…void

func(int,int,int

*);void

main(){int

a=11,b=99,c;func(a,b,&c);/*第一次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;func(a,b,&b); /*

第二次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;func(a,b,&a); /*

第三次调用func函数*/cout<<"a="<<a<<“,b="<<b<<",c="<<c<<endl;}void

func(int

x,int

y,int

*z){*z=y-x;}a=11,

b=99,

c=88a=11,

b=88,

c=88a=77,

b=88,

c=88虽然用指针作函数的参数可以使得形参的改变对相应的实参有效。但是,如果在函数中反复使用指针进行间接,会影响程序的可读性且容易产生错误,因此在C++语言中扩充了的概念,这样既可以实现指针所带来的功能,又使程序清晰易读。1.的概念(p182)

是一种特殊的变量,可以认为是一个变量的别名。定义

的一般格式:名=变量名;类型说明符&如:

int a

=

1;int &b

=

a;首先定义变量a,并初始化为1,然后定义b,并初始化为a,即b是a的别名,因此a和b是同一个单元。注意:定义是谁的别名。&为时一定要初始化,指明该

变量符,不代表地址.2.的简单使用#include

<iostream.h>void

main(){int

a=1;int

c=10;int

&b

=

a;cout

<<

a

<<

",

"

<<

b

<<",

"

<<

c

<<

endl;b

=

c;cout

<<

a

<<

",

"

<<

b

<<",

"

<<

c

<<

endl;b

=

20;cout

<<

a

<<

",

"

<<

b

<<",

"

<<

c

<<

endl;}程序运行结果:1,1,1010,10,1020,20,10定义b,并将其作为a的别名将c的值赋给b,不是将b作为c的别名3.

作为函数的参数例6.18

写一个函数,用

作为参数,交换函数中两个变量的值。#include

<iostream.h>void

swap(int

&x,

int

&y);void

main(){int

a,

b;a

=

10;b

=

20;swap(a,

b);cout

<<

a

<<

",

"

<<

b<<

endl;}void

swap(int

&x,

int

&y){int

temp;temp

=

x;x

=

y;y

=

temp;}程序运行结果为:20,10例6.18程序运行过程中参数值的变化图示10axyab

x20axby10temp20axby10temp10by10temp20202010用注意:

作参数时,函数的实参与形参在内存单元,因此形参的变化会使实参同时变化。3.数组作为函数参数A.数组元素作为函数参数——相当于简单变量作为函数参数单向值传递B.数组名作为函数参数——相当于指针变量作为函数参数单向地址传递A.数组元素作为函数参数例:有数组a和b,各含有10个元素,将它们对应地

逐个比较(即a[0]与b[0]比,a[1]与b[1]比,……)。

如果a数组中的元素大于b数组中的对应元素的数目多于b数组中元素大于a数组中对应元素的数目(例如,

a[i]>b[i]6次,b[i]>a[i]3次,其中i每次为不同的值),则认为a数组大于b数组,并分别统计出两个数组对应元素大于、等于和小于的次数。large(int

x,

int

y){int

flag;if

(x

>

y)

flag

=1;else

if

(x

<

y)flag

=

-1;else

flag

=

0;return

(flag);}函数large的功能:判断形参x和y的大小关系,返回1,0,-1三种函数值void

main(){int

large(intx,

int

y);int

a[10],

b[10],

i,

n=0,

m=0,

k=0;for(i

=

0;i

<

10;i++)cin>>a[i]for(i

=

0;i

<

10;i++)

cin>>b[

];for(i

=0;i

<10;i++){ if

(large(a[i],

b[i])

==1)

n++;else if

(large(a[i],

b[i])

==0)

m++;else

k++;}cout<<

"a[i]>b[i]"<<n<<

"times\na[i]=b[i]"

<<m<<

"times\na[i]<b[i]"<<k<<"times\n";if

(n>k) cout<<"array

a

is

larger

than

array

b\n

";else

if

(n

<

k)

cout<<"array

a

is

smaller

than

arrayb\n";else cout<<"array

a

is

equal

to

array

b

\n

";}主函数部分:以数组元素作为参数B.一维数组名作为参数数组名形参接受实参传递的数组首地址。实际上,C++编译系统将形参数组名作为指针变量来处理。b为形参数组名。当发生函数调用时,进行地址传送,把实参数组a的首地址传送给形参数组名b,于是b也取得该地址2000。于是a,b两数组共同占有以2000为首地址的一段连续内存单元。例如a[0]和b[0]都占用

2000~2003单元,当然a[0]等于b[0]。类推则有a[i]等于b[i]。a为实参数组,类型为整型。a占有以2000为首地址的一块内存区。数组名作为函数参数用数组名作函数参数与用数组元素作参数有几点不同:用数组元素作实参时,并不要求函数的形参也是

下标变量,对数组元素的处理是按普通变量对待的。用数组名作函数参数时,则要求形参和相对应的实

参都必须是类型相同的数组或指针。当形参和实参

二者不一致时,即会发生错误。在普通变量或下标变量作函数参数时,形参变量

和实参变量是由编译系统分配的两个不同的内存单

元。在函数调用时是把实参变量的值赋予形参变量,发生的值传送。在用数组名作函数参数时,不是进

行值的传送,是地址的传送,也就是说把实参数组

的首地址赋予形参数组名。形参数组名取得该首地

址之后,也就等于有了实在的数组。实际上是形参

数组和实参数组为同一数组,共同拥有一段内存空

间。3)在普通变量或下标变量作函数参数时,值传送是单向的,即只能从实参传向形参,不能从形参传回实参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,两者的终值是不同的。而当用数组名作函数参数时,实际上形参和实参为同一数组,因此当形参数组发生变化时,实参数组也随之变化。例.数组a中存放了一个学生5门课程的成绩,求平均成绩。float

aver(float

a[5]){

int

i;float

average,s=a[0];for(i=1;i<5;i++)s=s+a[i];average=s/5;retur

age;}void

main(){ float

sco[5],

averageint

i;for(i=0;i<5;i++)cin>>sco[i];average=aver(sco);cout<<average;}输入:67

69.5

79

91.5

98输出:average

score

is81.0000定义一个实型函数aver,有一个形参为实型数组a,长度为5。把各元素值相加求出平均值,返回给主函数。实现数组sco的输入。以sco作为实参调用aver函数,函数返回值送average,最后输出average值。例(判别一个整数数组中各元素的值,若大于0则输出该值,若小于等于0则输出0值)用数组名作函数参数。void

nzp(int

a[5]){ int

i;cout<<"\nvalues

of

array

a

are:\n";for(i=0;i<5;i++){if(a[i]<0)

a[i]=0;cout<<a[i]<<

"

";}}void

main(){ int

b[5],i;for(i=0;i<5;i++)cin>>b[i];nzp(b);for(i=0;i<5;i++)cout<<b[i]<<

"

";}输入:67

69

79-1

98输出:

67

69

79 0

9867

69

79 0

98函数nzp的形参为整型数组a,长度为5。按要求把负值单元清0,并输出形参数组a的值实参数组b也为整型,长度也为5输入数组b的值以数组名b为实参调用nzp函数数组b的终值和数组a是相同的一维数组名作为函数参数一维数组名作为函数参数4种等效形式:形参,实参都用数组名形参,实参都用指针变量形参用数组名,实参用指针变量形参用指针变量,实参用数组名情形一:实参和形参都是数组名。#include

…#define N

9void

output(int

a[],int

n){int

i;for(i=0;i<n;

i++)cout<<setw(5)<<acout<<"\n";}void

main(){int

x[N],i;for(i=0;i<N;i++)x[i]=2*i;output(x,N);}形参数组第一维大小形同虚设,无论如何定义,函数调用以后实际上是对实参数组进行操作,所以可以不指定第一维的大小注意:只能在实参数组的大小范围内使用形参数组为了方便被调函数的编写,通常另外设一个参数,用于传递数组元素的个数情形二:实参和形参都是指向数组的指针变量。#include

…#define N

9void

output(

int

*p

,int

n){ int

i;for(i=0;i<n;

i++)cout<<setw(5)<<*p++;cout<<"\n";}void

main(){ int

x[N],i;int

*q;for(i=0;i<N;i++)x[i]=2*i;q=x;output(q,N);}情形三:形参为数组名,实参为指向数组的指针变量。#include

…#define N

9void

output(

int

a[]

,int

n){ int

i;for(i=0;i<n;

i++)cout<<setw(5)<<*a++;cout<<"\n";}void

main(){ int

x[N],i;int

*q;for(i=0;i<N;i++)x[i]=2*i;q=x;output(q,N);}a是常量,应改为*(a+i)情形四:形参为指向数组的指针变量,实参为数组名。#include

…#define N

9void

output(

int

*p

,int

n){int

i;for(i=0;i<n;

i++)cout<<setw(5)<<*p++;cout<<"\n";}void

main(){int

x[N],i;for(i=0;i<N;i++)x[i]=2*i;output(x,N);}例:编写函数统计一个一维数组(10个元素)中非0元素的个数。int solve(int

b[],int

n){

int

sum=0,i;for(i

=

0;i

<n;i++)if(b[i]!=

0)sum++;return(sum);}void

main(){int

a[10],num,i;for(i

=0;i

<10;i++)cin>>a[i];num=solve(a,10);cout<<"num

=

"<<num;}/*一维数组名b作形参*//*一维数组名a作实参*/例:编一函数实现数组逆置。{ int

i,j,t;for(i=0,j=n-1;i<j;i++,j--){t=x[i];x[i]=x[j];x[j]=t;}

}void

main(){

int

i,a[10]={1,2,3,4,5,6,7,8,9,0};for(i=0;i<10;i++)

cout<<setw(3)<<a[i];cout<<"\n";fun(a,10);for(i=0;i<10;i++)

cout<<setw(3)<<a[i];}void

fun(

int

x[],int

n)

实参和形参都是数组名例:编一函数实现数组逆置。void

fun(

int

*x

,int

n){ int

*i,*j,t,m=(n-1)/2;for(i=x,j=x+n-1;i<=x+m;i++,j--){t=*i;*i=*j;*j=t;}

}void

main(){

int

i,a[10]={1,2,3,4,5,6,7,8,9,0};for(i=0;i<10;i++)

cout<<setw(3)<<a[i];cout<<"\n";fun(a,10);for(i=0;i<10;i++)

cout<<setw(3)<<a[i];}形参为指针变量,实参为数组名例:编一函数实现数组逆置。void

fun(

int

x[],int

n){ inti,j,t;for(i=0;i<=n/2;i++){j=n-i-1;

t=x[i];

x[i]=x[j];

x[j]=t;}

}void

main(){

int

i,a[10]={1,2,3,4,5,6,7,8,9,0},*p;for(i=0;i<10;i++)

cout<<setw(3)<<a[i];cout<<"\n";p=a;fun(p,10);for(i=0;i<10;i++)

cout<<setw(3)<<a[i];}形参为数组名,实参为指针变量例:编一函数实现数组逆置。void

fun(int

*x,int

n){ int

*i,*j,t,m=(n-1)/2;for(i=x,j=x+n-1;i<=x+m;i++,j--){t=*i;*i=*j;*j=t;}

}void

main(){

int

i,a[10]={1,2,3,4,5,6,7,8,9,0},*p;for(i=0;i<10;i++)

cout<<setw(3)<<a[i];cout<<"\n";p=a;fun(p,10);for(i=0;i<10;i++)

cout<<setw(3)<<a[i];}实参和形参都是指针变量例:编一函数实现采用选择排序法对数组中的整数按从小到大的顺序排列。void main(

){void

select(int

*a,int

n);int

a[10],i;cout<<"Input

10

numbers:";for(i

=0;i

<10;i++)cin>>a[i];cout<<“\n”;select(a,10);for(i

=0;i

<10;i++)cout<<setw(3)<<a[i];}void

select(int

*a,intn){

int

i,j,k,temp;for(i

=0;i<

n

-

1;i++){ k

=

i;for(j

=i+1;j

<

n;j++)if(*(a+j)

<*(a+k))

.k=j;if(k

!=i){ temp

=

*(a+k);*(a+k)

=*(a+i);*(a+i)

=

temp;}}}形参为指针变量,实参为数组名数组名做函数参数函数调用期间,形参二维数组就是实参二维数组例:有一个3x4的矩阵,设计函数求该矩阵所有元素中的最大值。void

main(

){ int

max_value(int

array[][4]);inta[3][4]=({1,3,5,7},{2,4,6,8},{15,17,34,12});cout<<"max

value

is

"

<<max_value(a);

}int

max_value(int

array[][4]){ inti,j,max;max

=

array[0][0];for(i

=0;i

<3;i++)for(j

=0;j

<4;j++)if(array[i][j]

>

max)max=array[i][j];return(max);}形参二维数组的第一维可以不指定大小,但是第二维必须指定用数组名作为函数参数时还应注意以下几点:形参数组和实参数组的类型必须一致,否则将引起错误。形参数组和实参数组的长度可以不相同,因为在调用时,只传送首地址而

查形参数组的长度。当形参数组的长度与实参数组不一致时,虽不至于出现语法错误(编译能通过),但程序执行结果将与实际不符,这是应予以注意的。void

nzp(int

a[8]){ int

i;cout<<"\nvalues

of

array

a

are:\n";for(i=0;i<8;i++){if(a[i]<0)a[i]=0;cout<<a[i]<<"

";

}}main(){ int

b[5],i;for(i=0;i<5;i++)cin>>b[i];nzp(b);for(i=0;i<5;i++)cout<<b[i]<<"

";}输入:67

69

79-1

98输出:

67

69

79

098

4082

256

167

69

79

0

98函数nzp的形参为整数组a,长度为8按要求把负值单元清0,并输出形参数组a的值a[5],a[6],a[7]是无意义的实参数组b也为整型,长度为5输入数组b的值以数组名b为实参调用nzp函数数组b的终值和数组a是不相同的3)在函数形参表中,允许不给出形参数组的长度,或用一个变量来表示数组元素的个数。例如可以写为:void

nzp(int

a[])或void

nzp(int

a[],int

n)其中形参数组a没有给出长度,而由n值动态地表示数组的长度。n的值由主调函数的实参进行传送。由此上例可以改写为:void

nzp(int

a[],int

n){ int

i;cout<<"\nvalues

of

array

a

are:\n";for(i=0;i<n;i++){if(a[i]<0)

a[i]=0;cout<<a[i]<<"

";

}}void

main(){ int

b[5],i;cout<<"\ninput

5

numbers:\n";for(i=0;i<5;i++)cin>>b[i];nzp(b,5);for(i=0;i<5;i++)cout<<b[i]<<"

";}其中形参数组a没有给出长度,而由n值动态地表示数组的长度。n的值由主调函数的实参进行传送。在main函数中,函数调用语句为nzp(b,5),其中实参5将赋予形参n作为形参数组的长度。输入:67

69

79-1

98输出:67

69

79

0

9867

69

79

0

984)

数组也可以作为函数的参数。在函数定义时对形参数组可以指定每一维的长度,也可省去第一维的长度。因此,以下写法都是合法的。int

MA(int

a[3][10])或int

MA(int

a[][10])但是如下写法是错误的:int

MA(int

a[3][

])√×字符数组作为函数参数函数调用期间,形参字符串就是实参字符串例:改用两个字符指针变量作形参void

stringcopy

(char

*p,

char

*q){while(

(*p++=*q++)

!=‘\0’

);}例:

编写一个字符串

函数,并在主函数中调用该函数,验证其正确性。#include

…void

stringcopy

(char

s[],

char

*t){int

i=0;while(*t

!=

'\0'){s[i]=*t;i++;t++;}s[i]=

'\0';}void

main(){char

str1[]="I

love

Beijing!"

;char

*str2="I

love

China!

"

;stringcopy

(

str1,

str2

)

;cout<<"str1="<<str1<<"\n"<<"str2="<<str2;}将指向字符串首字符的指针q移到字符串末尾while(*q)

q++;q--;while(*q++);q--;√×例:将一个字符串s1中第k个字符开始的后续字符组成子串s2void

copysubstring(char

*s1,char

*s2,int

k){ s1=s1+k

-1;while(

*s1!='\0')*s2++=*s1++;*s2=‘\0’;}例.将一个字符串s1中第k个字符开始的n个后续字符组成子串s2,不足则取后续所有字符void

copysubstring(char

*s1,

char

*s2,

int

k,

int

n){

s1=s1+k-1;while(

n>0

&& *s1

!=

'\0'){

*s2++=*s1++;*s2=‘\0’}n--

}字符指针作函数参数例.把一个字符串的内容(1)数组传给数组:void

cpystr(char

pas[],char

pbs[]){int

i=0;while(pas[i]!='\0'){pbs[i]=pas[i];i++;}pbs[i]=‘\0’;}void

main(){char

pa[]=“I

am

a

boy.",pb[20];cpystr(pa,pb);cout<<"a="<<pa<<"\nb="<<pb;}运行结果:a=I

am

a

boy.b=I

am

a

boy.Iamaboy.\0到另一个字符串中。papbpas[0]pbs[0]pas[i]pbs[i]循环结束赋值\0(2)指针传给数组:void

cpystr(char

pas[],char

pbs[]){

int

i=0;while(pas[i]!='\0'){pbs[i]=pas[i];i++;}pbs[i]=‘\0’;}void

main(){char

pa[]=“I

am

a

boy.",pb[20];char

*a=pa,*b=pb;cpystr(a,b);cout<<"a="<<a<<"\nb="<<b;}Iamaboy.\0papbpas[0]pbs[0]ab(3)数组传给指针:void

cpystr(char

*pas,char

*pbs){

while(*pas!='\0'){*pbs=*pas;pas++;pbs++}*pbs=‘\0’;}void

main(){char

pa[]=“I

am

a

boy.",pb[20];cpystr(pa,pb);cout<<"a="<<pa<<"\nb="<<pb;}Iamaboy.\0papbpaspbs(4)指针传给指针:void

cpystr(char

*pas,char

*pbs)Iamaboy.\0paspbsab{

while(*pas!='\0'){*pbs=*pas;pas++;pbs++}*pbs=‘\0’;}cpystr函数体可改写:①

while((*pbs=*pas)!='\0'){pas++; pbs++;

}②

while((*pbs++=*pas++)!=‘\0’);③

while(*pas)

*pbs++=*pas++;*pbs=‘\0’④

while(*pbs++=*pas++);7.4

函数的嵌套和递归调用函数的嵌套调用是指一个函数在被调用时其本身又调用了其他函数。123456789例.main

(

)p1(

){

cout<<”m***\n”;{cout<<”p1***\n”;p3

();p2

();cout<<”m+++\n”;p2

();cout<<”p1+++\n”;}cout<<”m!!!\n”;

}p2

(

)p3

(){cout<<”p2\n”;

}{

cout<<”p3***\n”;p2

();cout<<”p3+++\n”;p1

();cout<<”p3!!!\n”;}12453

67891011main

(

){……p3();……p2

();……}P3(){

……p2

();……p1

();……}P2(){

……}P2(){

……}P2(){

……}P1(){

……P2……}void

main(){ int

m,n,t;float

c(int,

int);cin>>m>>n;if(n>m)

cout<<"Input

error";else

cout<<c(m,n);}floatfac(int

t)/*求t!*/{ int

i;float

s=1;for(i=1;i<t;i++)

s*=i;return

s;}{ float

f,fac(int);f=fac(m)

/

(fac(n)*fac(m-n));return

f;}例.求组合数mC

nMain函数中调用C函数C函数中三次调用fac函数mfloat

c(int

m,

intn) /*求C

n

*/用二分法求下面方程在(-10,10)之间的根2x3-4x2+3x-6=0ab此两点一定为异号才有解与a异号,中点2在左边中点1b与b异号,中点3在左边中点3中点2#include

…float

f(float

x){return

((2*x-4)*x+3)*x-6;}float

root(float

x1,float

x2){float

x,y,y1;do

{

x=(x1+x2)/2;

y=f(x);

y1=f(x1);if

(y*y1>0)

x1=x;

else

x2=x;(fabs(y)>=1e-6);}whilereturn

x;}void

main(){floatx1,x2;do

{cout<<"input

x1,x2:";cin>>x1>>x2;}while(f(x1)*f(x2)>=0);cout<<"A

root

ofequation

is

"<<root(x1,x2);}计算2x3-4x2+3x-6的值中点函数值左边函数值以上两函数值同号,中点为新的左端点,否则中点为新的右端点做到y值近0为止两边界点函数值为异号才有解直接调用函数7.4.2函数的递归调用函数的递归调用:在调用一个函数的过程中又直接或间接的调用函数自身.在递归调用中,主调函数又是被调函数。intf(intx){

int

y;…z=f(y);…

return

z;}直接递归调用7.4.2函数的递归调用间接递归调用func1(intn){inty;┇func2(y);┇}func2(intx){int

m;┇func1(m);┇}7.4.2函数的递归调用一个递归函数运行时有可能无休止地调用其自身,这

当然是不正确的。为了防止递归调用无终止地进行,

必须加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。递归函数的2要素:1.递归公式2.递归结束的条件例.

计算

4!

4!—————————————24↓3!*4————————————6*4=24↓2!*3————————————2*3=6↓1!*2————————————1*2=2↓n>1 n!

→

(n-1)!*nn=1 n!

→

1终止条件递归公式int f

(

int n

){

int m

;if

(

n==1

)

m=1;elsem=

f

(n-1)*n;return

(

m

);}void

main(

){cout<<“

4!=

“<<f

(4)

;}实参递归调用终止条件例:5个人坐在一起报岁数,问第5个人几岁?他说比第4

个

两岁;问第4个人几岁?他说比第3个

两岁;

问第3个人几岁?他说比第2个

两岁;问第2个人几岁?他说比第1个两岁;最后问第1个人几岁?他说10岁。这是一个递归问题:要求第5个人的

,要先知道第4个人的

;要求第4个人的

,要先知道第3个人的;要求第3个人的

,要先知道第2个人的年龄;……得出:age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10得出公式:比前一位

大2岁,无终止调用10岁有终止age(n

1)

2n

1n

1age(n)

10递归公式12141618int age(

int n

){

int c

;if

(

n==1

)

c=10;else c=

age

(n-1)+2;return

(

c

);}void

main(

){cout<<age

(5)

;}实参递归调用终止条件函数的重载(p100)所谓函数的重载是指完成不同功能的函数可以具有相同的函数名。C++的编译器是根据函数的实参来确定应该调用哪一个函数的。int fun(int

a, intb){ return

a+b;

}int fun

(int

a){ return

a*a;

}void

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论