第8 章函数文档格式.docx
《第8 章函数文档格式.docx》由会员分享,可在线阅读,更多相关《第8 章函数文档格式.docx(36页珍藏版)》请在冰豆网上搜索。
![第8 章函数文档格式.docx](https://file1.bdocx.com/fileroot1/2023-1/22/5e75a5fe-fa76-44ac-bb3c-07bd05248d78/5e75a5fe-fa76-44ac-bb3c-07bd05248d781.gif)
识符;
3.函数原型及其一般格式:
(P153)
【说明】在函数的声明中也可以不写形参名,只写形参的类型,这种函数声明称之为函数原型。
floatadd(float,float);
【说明】因为编译系统部检查函数名,故函数名有无都无所谓。
4.对被调函数不需声明的情形:
(P154)
①被调函数定义在主调函数之前;
intmax(intx,inty){}main(){max(x,y);
}
②在所有函数定义之前,在函数的外部已作声明;
③函数的类型为int、char型时可不作声明(但实参和形参的类型应一致,否则可能出错)
四、函数的调用(P150)
1.函数调用的一般格式:
函数名(实际参数列表)(P150)
【说明】
①即使函数没有参数,但函数名后面的()不能省略。
②实际参数在类型、个数、顺序上要求和形式一致;
实参与形参按顺序对应,一一传递数据;
③系统对数据参数的求值顺序不定;
者将影响结果(TC中为从右到左)。
(P150)
50
intsa(inta,intb){
if(a>
b)return
(1);
elsereturn(a==b?
0:
-1);
main(){
inti=3;
printf(“”,sa(i,i++));
intsa(inta,intb){
return(a==b?
0:
a>
b?
1:
inti=2;
printf("
%d"
sa(i,++i));
2.函数调用的方式和调用形式(P150)
1)调用的方式:
(1)函数语句。
printf(“Thisisacprogram”);
(2)函数表达式。
c=max(2,3);
(3)函数参数(函数作为其他函数的参数)。
mx=max(a,max(b,c))
2)调用的形式:
(1)传值调用:
传递数据本身,实参与形参互不影响(实参与形参分别占用不同的存储空间)
(2)传址调用:
传递装载数据的空间的地址;
实参与形参分别占用不同的存储空间
(3)嵌套调用:
函数之间互相调用
(4)递归调用:
函数自己调用自己
3.函数的传值调用
【传值调用过程】
①实参与形参分别占用不同的存储空间,形参值的改变不能传回给对应的实参;
②形参的存储空间是在函数被调用时分配的,然后将实际参数的值传递到该空间中。
③函数调用结束,形式参数所占的存储空间自动释放;
【实例1】voidswap(intx,inty){
x=x+y,y=x-y,x=x-y;
swap:
x=%dy=%d\n"
x,y);
inta=3,b=5;
swap(a,b);
main:
a=%db=%d\n"
a,b);
结果为:
x=5y=3
a=3b=5
【实例2】用数组元素作为参数(实际参数,形式参数为变量)
voidswap(inta,intb);
inta[]={4,9};
a[0]=%da[1]=%d\n"
a[0],a[1]);
swap(a[0],a[1]);
51
voidswap(inta,intb){
intt;
t=a,b=a,b=t;
a[0]=4a[1]=9
4.函数的传地址调用(例:
8.13,P166)
【传址调用过程】①实参与形参分别占用同一的存储空间,形参值的改变将传回给对应的实参中;
【实例1】用指针变量作为参数(形式参数)
voidswap(int*x,int*y){
*x=*x+*y;
*y=*x-*y;
*x=*x-*y;
*x=%d*y=%d\n"
*x,*y);
main(){inta=3,b=5;
*x=5*y=3
a=5b=3
【实例2】用一维数组名作为参数(实际参数和形式参数)
voidswap(inta[2]);
swap(a);
voidswap(intb[2]){
t=b[0];
b[0]=b[1];
b[1]=t;
a[0]=9a[1]=4
【实例3】用数组名作为参数(实际参数用二维数组,形式参数用一维数组)
intmaxvalue(intb[]);
intn;
inta[][4]={{100,300,500,980},{12,24,36,57},{10,20,30,40}};
max=%d\n"
maxvalue(*a,12));
intmaxvalue(intb[],intn){
inti=0,k=0;
52
for(;
i<
n;
i++)if(b[i]>
b[k])k=i;
returnb[k];
5.函数嵌套调用(P155):
voidsb(){
Subfunction\'
sb()\becalledbysunfunction\'
sa()\'
\n"
);
voidsa(){
sb();
sa()\becalledbysubfunction\'
SubFunction\'
becalledbymainFunction.\n"
sa();
6.函数递归调用(P158):
在函数的过程中出现直接或间接调用该函数本身
1)直接递归调用:
在函数的过程中直接调用该函数本身。
【例1】求n!
(P160)
floatfac(intn){
floatf=1;
if(n<
0){
n<
0,DataError"
exit
(1);
if(n==0||n==1)f=1;
elsef=fac(n-1)*n;
return(f);
n=?
"
scanf("
&
n);
%d!
=%-15.0f"
n,fac(n));
if(n==0||n==1)return
(1);
elsereturn(n*fac(n-1));
【例2】要求不用循环语句(用直接递归),求1+2+3+┅┅+100(n属于正自然数)
longsum(intn){
if(n>
0)return(n+sum(n-1));
elsereturn(0);
53
sum=%ld"
sum(100));
【例3】输入一字符串后,再反向输出(用直接递归)。
程序1:
voidconver(char*p){
charq=*p;
if(*p)conver(++p);
%c"
q);
char*p="
;
Inputastring:
gets(p);
conver(p);
程序2:
#include"
stdio.h"
voidgt(char);
gt(getchar());
voidgt(chars){
if(s!
='
\n'
)gt(getchar());
s);
【例4】求1-100的合计(用直接递归,n大于100,且由参数输入)。
floatsum(int);
sum=%f"
sum(1000));
floatsum(inti){
if(i>
0)return(i+sum(i-1));
实现系统函数strcmp()的功能
string.h"
intsum=0;
voidum(inti,intn){
if(i<
=n)um(sm(i),n);
intsm(inti){
sum=sum+i;
return(i+1);
intscmp(chara,charb){/*实现系统函数strcmp()的功能*/
*b&
&
*a;
a++,b++)if(*a!
=*b)break;
return(*a-*b);
54
main(){chara[]="
China"
b[]="
American"
strcmp(%s,%s)=%d\n"
a,b,scmp(a,b));
um(1,100);
1+2+...+100=%d\n"
sum);
【例5】Hanoi问题(用直接递归)(P161)。
【例6】求1!
+2!
+……+n!
(用直接递归)(P161)。
floata=1,m=0;
voidsum(inti,intn){
if(i<
=n)sum(ss(i),n);
intss(inti){
a=a*i;
m=m+a;
inti=1,n=10;
sum(i,n);
1!
+2!
+....+%d!
=%f"
n,m);
floatfac(inti){
floatp=1;
intk=1;
k<
=i;
k++)p=p*k;
=%f\n"
i,p);
return(p);
main(){floatsum=0;
inti=1;
=10;
i++)sum=sum+fac(i);
+....+10!
程序3:
floatpt(intn){
=1)return
(1);
elsereturn(n*pt(n-1));
floatfat(inti){
elsereturn(fat(i-1)+pt(i));
fat(10));
55
程序4:
1)return(n*fac(n-1));
elsereturn
(1);
floatsum(intn){
0)return(fac(n)+sum(n-1));
intn=1;
20;
n++)printf("
+"
n);
n,sum(20));
程序5:
#defineN10
floatfas(intn){
staticfloatp=1;
p*=n;
floatsm(intn){
=N)return(fas(n)+sm(n+1));
N;
for(n=1;
n,sm
(1));
【例8】用循环和递归求任意两个正整数的最大公约数
intgcd(intm,intn){
if(m%n)gcd(n,m%n);
elsereturn(n);
main(){inta=26,b=20,cs=0,r;
GCDINSUNF:
%d\n"
gcd(a,b));
a=20,b=26;
while((r=a%b)!
=0){
a=b;
b=r;
cs++;
GCDINMAIN:
%dcs:
%d"
b,cs);
intscmp(char*a,char*b){
56
chara[]="
2)间接递归调用:
在函数的过程中直接调用其他函数,其他函数又调用该函数本身。
五、函数的参数、返回值与属性(P164)
1.函数参数的类别(实际参数:
调用函数时传递;
形式参数:
定义函数时指定):
1)实际参数:
简称为实参。
有两种形式:
值参数:
传递的是数值;
址参数:
传递的是地址;
(1)值参数的具体形式:
实参数的形式可以是:
常量、变量(含数组元素)、表达式、函数调用;
(2)值参数的数据类型:
int(6种)、char(2种)、float、void、结构体(或共同体)类型;
【说明】对应形式参数值的改变不影响实际参数的值;
因它们分别占用不同的存储单元(内存空间);
(3)址参数的具体形式:
指针、数组名(一维数组名或二维数组必须是列地址);
(4)址参数的数据类型:
指针、数组;
【说明】①实参的数据类型:
int(6种)、char(2种)、float、void、指针、数组名、结构体、共同体;
②对应形参数值的改变影响实参的值;
因它们占用同一的存储空间;
2)形式参数:
简称形参,在定义函数时指定其名称和数据类型;
(1)形参的具体形式:
只能是一般变量名、数组名、指针变量;
不能是常量、表达式或函数调用;
(2)形参的数据类型:
int(6种)、char(2种)、float、void、结构体、共同体、指针、数组;
(P165)
①实际参数与形式参数的数据类型应该一致,否则可能发生类型转换,具体情形有:
int(short,long)→unsignedint;
int(short,long)→char;
int→long;
int(short,long)→float;
double→float;
char→unsignedchar及其逆运算;
②形参的形式只能是一般变量名或数组名或指针变量;
实际参数的形式和类型要而与形式参数的形式
和类型对应(相容);
当实参是值参时(形如常量、变量、数组元素、表达式、函数调用),对应
的形式参数只能是一般变量的形式;
当实参是地址时(形如变量(数组元素)地址、数组名、指针
变量),对应的形式参数只能是地址形式(数组名或指针变量)。
③实参数组与形参数组的大小可以不一致,因编译系统对此不做检查;
只将其首地址传递给形参;
④形参数组的可以不指定大小,另设一参数传递其大小(当为字符数组时可以不传递数组的大小);
⑤当实参为址(指针、数组名)传递时,对应形式参值的改变要影响实参值的改变;
因它们共同占用
同一存储单元(即内存空间)。
P166
⑥实参为一般变量、数组名、指针变量时,应在主调函数中对其给予定义。
2.函数的类型
通常把函数返回值的类型称之为函数的类型,即定义时所指定的类型(函数的类型以定义的类型为
准)。
【说明】①int和char型函数在定义时可以不指定其类型(系统默然指定为整型)
②函数在定义时未指定其类型,系统默然指定其类型为整型
3.函数的返回值
①函数的返回值通过程序中的return(表达式)返回;
57
②在程序中有多个表达式时,由被执行到的第一个return(表达式)返回函数的结果值;
③函数在返回时将返回值的类型自动转化为该函数定义的类型;
即以定义的类型为准;
④函数可以没有返回语句。
⑤当函数类型指定为void类型时,在函数中可有return语句,但不能返回表达式否则出错;
【函数递归实现的原理与递归终结条件】
函数的递归调用从某种意义上说相当与循环,但又有别于循环。
函数的递归调用就是在执行过程中,函
数的可执行部分尚未终止,接着又直接或间接的调用函数自己。
函数的递归调用分为直接递归和间接递
归。
直接递归就是一次函数的执行尚未结束,在本身的函数体中又调用自己。
函数直接递归调用的关键是:
怎样才能实现递归调用?
怎样使递归调用终结?
终结条件是什么?
1)实现有条件的递归调用,即当条件满足时函数才递归调用,否则就结束递归调用。
2)递归调用的终结条件:
(1)至少有一次不用递归调用的情况,关键是在不同的情况如何实现。
(2)递归实现的条件要能够向非递归转化。
要不然可能造成无限的递归调用;
输入若干字符,以回车作为输入结束标志。
要求反向输出。
若输入为:
ABCDEFGHIJK↙
要求输出:
KJIHGFEDCBA
自己定义函数如下:
voidsa(charch){
if(ch!
='
)sa(getchar());
/*递归实现的条件ch!
*/
printf(“%c”,ch);
/*自动变量的特点,不同函数中的同名变量互不影响*/
请注意该递归调用过程中递归条件是怎样向非递归转化的?
思考题:
将上述函数改为如下程序后,能否实现上述要求?
为什么?
elseprintf(“%c”,ch);
【问题】利用静态变量和自定义函数与函数的递归调用实现求1-100的合计,不能用循环结构。
8.2函数的属性(内部函数与外部函数)
根据函数能否被其他函数调用,将函数分为内部函数和外部函数
一、内部函数
1.概念:
如果一个函数只能被本文件中的其他函数所调用,则称之为内部函数;
又称之为静态函
数。
2.定义格式:
static类型名称函数名称(形式参数列表)
【说明】不同文件之间的静态同名函数互不影响。
二、外部函数
如果一个函数能被本文件外的其他函数所调用,则称之为外部函数;
又称之为全局函数。
extern类型名称函数名称(形式参数列表)
【说明】在需要调用此函数的文件中,用extern声明所用的函数为外部函数。
三、多个源文件的编译、连接(P184)
【工程文件的建立】
1.先编辑每个需要的源文件
2.编辑工程文件(即项目文件)(.prj);
工程文件中只包含需要连接、编译的每个源文件名称即
可。
3.通过alt+p打开主菜单,选择“ProjectName”,输入工程文件名
4.最后编译为一个可执行文件
【外部函数调用实例分析:
多个源文件的连接、编译】
58
/*enterab.prj文件的内容:
*/
entabgetmaxgetmingetsum
/*源程序文件entab.c的内容*/
inta,b;
/*externintmax(int,int);
externintmin(int,int);
externintsum(int,int);
Inputab:
scanf("
%d%d"
a,&
b);
max=%d\nmin=%d\nsum=%d\n"
max(a,b),min(a,b),sum(a,b));
/*源程序文件getmin.c的内容*/
intmin(inta,intb){
return(a>
b:
a);
/*源程序文件getmax.c的内容*/
intmax(inta,intb){
a:
/*源程序文件getsum.c的内容*/
intsum(inta,intb){
return(a+b);