第八章 函数.docx
- 文档编号:14724734
- 上传时间:2023-06-26
- 格式:DOCX
- 页数:34
- 大小:31.13KB
第八章 函数.docx
《第八章 函数.docx》由会员分享,可在线阅读,更多相关《第八章 函数.docx(34页珍藏版)》请在冰点文库上搜索。
第八章函数
第八章函数
在计算机科学领域,人们经常采用逐步分解、分而治之的方法解决一些复杂问题。
所谓分而治之的解决策略是指将一个大问题分解成若干子问题,如果每个子问题还是比较复杂,可以继续分解,直到子问题能够比较容易地解决为止。
例如,在开发网络协议的时候,往往采用分层模型来降低协议设计的复杂性。
在设计一个复杂的应用程序时,程序员往往会将整个程序划分为若干独立命名且可独立访问的模块,每个模块完成一个子功能,将所有模块集成起来就是一个功能完善的整体。
分而治之思想在程序设计中的实现称为模块化程序设计。
C语言中,函数就是程序模块。
C语言将模块中的代码定义在{}中,并用一个标识符对模块命名,称为函数。
函数写好后,可被用户反复调用,而无须关心实现细节。
例如,排序是一个程序设计中经常要用到的操作,我们可以编写一个对n个整数进行排序的函数。
只要程序设计时要对整数排序就可以很方便地调用排序函数,而无须重写实现排序的代码。
从中我们不难发现,使用函数有利于代码的重用,避免一切事情从头做起,提高用户的编程效率。
8.1函数的定义和调用
一、函数定义和调用的基本语法格式
1.函数定义的基本语法格式
[返回类型]函数名([形式参数变量说明列表])
{
语句序列/*函数体*/
}
说明:
(1)中括号中的语法成分可以省略,例如返回类型和形参变量说明列表在定义函数时可以没
有。
(2)在C语言中一个函数就是一个功能独立的模块,为了能够调用函数,必须对函数命名,
函数名要符合C语言中标识符的命名规则。
(3)形参变量说明列表的基本形式是:
(数据类型变量名1,数据类型变量名2,…,数据类
型变量名n),每个形参变量的定义包括数据类型和变量名。
使用形参变量是为了能够保存函数执行时要用到的一些数据,这些数据是由调用者(往往是另一个函数)向被调函数提供的。
(4)实现函数主要功能的语句包括在一对花括号中,称为函数体。
(5)一个函数往往需要将结果数据返回给调用者,结果数据的类型决定了函数的返回类型,在函数体中使用return语句返回结果数据。
如果一个函数没有任何结果数据返回,则函数的返回类型为void。
2.函数调用的基本语法格式
(1)有参函数的调用
函数名(实参1,实参2,…,实参n)
说明:
调用有参函数时,必须向函数提供一些数据(将被保存在函数的形参变量中),这些数据被称为实参,放在函数调用运算符“()”中,多个实参之间用逗号隔开。
各种有值表达式都可以作为实参。
(2)无参函数的调用
函数名()
说明:
调用无参函数时不需要向其传递数据(无参函数本无形参变量),因此函数调用运算符不包含任何实参。
二、有参数有返回值函数的定义和调用
【例8.1】写一个求n!
的函数(n<13)。
intsum(intn)
{
ints=0;
inti;
for(i=1;i<=n;i++)
s=s+i;
returns;
}
main()
{
inti=10;
intresult;
result=sum(i);
printf("%d\n",result);
printf("%d\n",sum(2*i));
}
说明:
(1)函数调用表达式(如sum(i)和sum(2*i))出现在main函数的函数体中,所以main函数
相对于sum函数是调用者,sum是被调函数。
(2)函数sum是有参函数,主要功能是计算某个整数的阶乘,所以在调用sum函数时必须向
其提供一个整型数据(即实参),实参可以是各种表达式,在本例程序中第一次调用sum
函数提供的实参是变量i,第二次调用sum函数提供的实参是表达式2*i。
提供的实参值将被存储在sum函数的形参变量中,可以认为在调用有参函数时存在赋值,即“形参变量=实参的值”。
(3)函数sum同时又是有返值的函数,通过return语句将阶乘结果返回给调用者。
所以关
于sum函数的调用表达式其实都是有值表达式,这些表达式的值既可以通过printf打
印出来,如本例程序中的“printf("%d\n",sum(2*i));”,也可以进一步参与其他运算,
如本例程序中的“result=sum(i);”。
【例8.2】定义函数max,求出两个整数中较大值并返回。
另外,在main函数中调用max。
#include
intmax(intx,inty)
{
if(x>y)returnx;
elsereturny;
}
main()
{
inta,b;
scanf("%d,%d",&a,&b);
printf("%d\n",max(a,b));
}
二、有参数无返回值的函数的定义和调用
【例8.3】编写函数display_message,该函数根据调用者提供的成绩数据显示相应等级:
A(优)、B(良)、C(中)、D(及格)以及E(不及格)。
#include
voiddisplay_message(intscore)
{
printf("score=%d\n",socre);
if(score>=90)printf("A\n");
else
if(score>=80)printf("B\n");
else
if(score>=70)printf("C\n");
else
if(score>=60)printf("D\n");
elseprintf("E\n");
}
main()
{
ints;
charresult;
scanf("%d\n",&s);
display_message(s);
}
说明:
无返值函数只能单独调用。
无返值函数调用表达式不能参与其他操作。
无返值函数调用表达式其实就无值表达式。
三、无参数有返回值函数的定义和调用
【例8.4】今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?
#include
sunziproblem()
{
intn=1;
while((n%3!
=2)||(n%5!
=3)||(n%7!
=2))n++;
return(n);
}
main()
{
printf("%d\n",sunziproblem());
}
说明:
(1)无参函数在定义时没有任何形式参数变量,有两种表示方法:
一是让形参表列为空;二是用关键字void显式说明。
(2)调用无参数函数时,不需要向其提供任何实参。
(3)函数sunziproblem没有返回类型,默认返回类型为int。
(4)用计算机程序解决孙子问题时,首先根据同余理论,知道肯定有解,然后用穷举法求出最小的正整数解。
四、无参数无返回值函数的定义和调用
【例8.5】下面的函数showbagua是一个即无形式参数,又没有返回值的函数,其功能仅仅是粗略地描绘了一个八卦图案。
#include
voidshowbagua(void)
{
intmidx,midy;
intradius=160;
midx=getmaxx()/2;
midy=getmaxy()/2;
circle(midx-radius/2,midy,11);/*左边的小圆,由于视觉差异,左边小圆半径要小*/
floodfill(midx-radius/2-5,midy,WHITE);/*白色填充*/
circle(midx+radius/2,midy,12);/*右边的小圆*/
floodfill(midx+radius/2+5,midy,BLACK);/*黑色填充*/
setcolor(WHITE);
arc(midx,midy,90,270,radius);/*左半圆弧*/
arc(midx,midy,207,90,radius);/*右半圆弧*/
arc(midx+46,midy-radius/2+18,120,240,92);/*中间上半圆弧,弧度120*/
arc(midx-46,midy+radius/2-18,300,60,92);/*中间下半圆弧,18是修正值*/
floodfill(midx-20,midy,BLACK);/*右八卦黑色*/
floodfill(midx+20,midy,WHITE);/*左八卦白色,没有颠倒阴阳吧?
*/
}
main()
{
intgdriver=EGA,gmode=EGAHI;
initgraph(&gdriver,&gmode,"c:
\\tc");
setbkcolor(BLACK);
cleardevice();
showbagua();
getch();
closegraph();
}
说明:
函数showbagua是一个无返回值函数,所以只能独立调用,又因为该函数没有形参变
量,所以调用时不需要向其提供任何实参,即showbagua();
8.2函数定义和调用时要注意的问题
一、return语句的使用
1.void函数中使用return语句
通常情况下,void函数(即无返回值函数)中不需要使用return语句,当void函数执行到“}”时自然就结束执行,程序流程回到调用者。
如果需要提前结束void函数的执行,也可以在函数中使用不带返回值的return语句(即return;)。
函数遇到第一条不带返回值的return语句即结束执行并返回。
【例8.6】void函数中使用return语句。
#include
voidmenu(charch)
{
if(ch=='1')
{
printf("Youarehopeless!
\n");
return;
}
if(ch=='2')
{
printf("Youaregreat!
\n");
return;
}
if(ch=='3')
{
printf("Youaretheworst!
\n");
return;
}
}
main()
{
charc;
printf("Selectanoption(1,2,3)\n");
c=getchar();
menu(c);
}
2.非void函数中使用return语句
非void函数(即有返回值的函数)中必须使用return语句将值返回给调用者。
【例8.7】编写一个能计算某年某月的天数的函数。
#include
intgetmonthdays(intyear,intmonth)
{
switch(month)
{
case1:
return31;
case3:
return31;
case5:
return31;
case7:
return31;
case8:
return31;
case10:
return31;
case12:
return31;
case4:
return30;
case6:
return30;
case9:
return30;
case11:
return30;
case2:
if(year%4==0&&year%100!
=0||year%400==0)
return29;
elsereturn28;
}
}
main()
{
inty,m;
scanf("%d.%d",&y,&m);/*2009.6*/
printf("%ddays!
\n",getmonthdays(y,m));
}
二、将函数调用作为实参
调用有参函数时必须向其提供实参,实参是一个有值表达式,而对有返回值函数的调用本身就是有价值表达式,故可将有返回值函数的调用作为另一个有参函数调用的实参。
【例8.8】编写一个求两整数和的函数,在函数main调用该函数实现求四个整数的和。
#include
intsum(intx,inty)
{
return(x+y);
}
main()
{
inta,b,c,d,result;
scanf("%d,%d,%d,%d",&a,&b,&c,&d);
result=sum(sum(a,b),sum(c,d));
printf("%d\n",result);
}
【课内编程练习8.1】编写一个求两整数中大者的函数,调用该函数计算三整数中最大的整数。
三、参数传递
调用有参函数时,被调函数和调用者之间要进行数据的传递。
具体过程时,系统先为被调函数的形参变量分配内存空间,然后将调用者提供给被调函数的实参表达式的值传递给(存储)形参变量,这种参数传递是单向的值传递。
【例8.9】定义一个swap函数,用来交换两个实参变量的值。
#include
voidswap(intx,inty)
{
inttemp=x;
x=y;
y=temp;
}
main()
{
inta=1,b=2;
swap(a,b);
printf("a=%d,b=%d\n",a,b);
}
四、类型兼容
1.实参和形参的类型要兼容
实参表达式值的数据类型应该要和形参变量的数据类型一致,如果两者的数据类型不一致,需将实参表达式值的数据类型转换为形参变量的数据类型,再进行参数传递。
#include
voidtestparamtype(inti)
{
printf("%d\n",i);
}
main()
{
doubled=3.1415926;
testparamtype(d);
}
2.返回表达式的类型与函数的返回类型要兼容
return语句返回的结果表达式值的数据类型要与函数的返回类型一致,如果两者的数据类型不一致,以函数的返回类型为准。
#include
inttestrettype(doublex,doubley)
{
returnx+y;
}
main()
{
doubleresult=testrettype(3.5,-0.2);
printf("%f\n",result);
}
五、函数原型声明
1.何时进行函数原型声明
前面给出的所有例题都有一个共同的特点,就是我们将被调函数定义在调用者的前面,其中的调用者都是main函数。
如果反过来,函数调用在前而被调函数的定义在后的,就需要在调用者函数体的开始位置上声明被调函数的原型。
2.如何声明函数原型
函数原型是指函数定义中除函数体以外的其他部分,包括函数的返回值类型、函数名和函数形参列表中各个形参变量的数据类型。
例如:
main()
{
intmax(int,int);
inta,b;
scanf("%d,%d",&a,&b);
printf("%d\n",max(a,b));
}
intmax(intx,inty)
{
if(x>y)returnx;
elsereturny;
}
说明:
(1)简单理解函数原型,就是函数的头部,只是在说明形参列表时只要给出所有形参变量的
类型,形参变量名在声明函数原型时可以省略。
(2)C语言有一个特点,凡是提前使用的对象都要声明。
(3)声明语句一定位于{}的最开始位置,例如函数原型声明语句、变量定义语句等等。
(4)被调函数原型既可以在调用者函数体中声明,这对某个特定的调用者是可见的;被调函
数原型也可以在所有函数的外面声明,这对要调用该函数的所有调用者都可见。
六、数组作为函数参数
【例8.10】形参数组
#include
main()
{
inta[10],i;
voidadd_arrayelem(int[],int);
for(i=0;i<10;i++)scanf("%d",&a[i]);
add_arrayelem(a,10);
for(i=0;i<10;i++)printf("%d",a[i]);
printf("\n");
}
voidadd_arrayelem(intb[],intn)
{
inti;
for(i=0;i printf("sizeof(b)=%d\n",sizeof(b)); } 说明: (1)数组作为被调函数的形参时,往往省略其长度,所以在被调函数中还需定义另一个整型变量(如本例add_arrayelem函数中的形参变量n)来接受调用者传递过来的实参数组的长度。 (2)从程序的运行结果中不难发现,当把实参数组传递给形参数组后,形参数组的变化会导致实参数组的同步变化。 (3)事实上在编译时,编译器将形参数组转换成相应类型的指针变量,例如本例add_arrayelem中的形参数组intb[],将被转换为一个int指针变量“int*b”,这点可用sizeof运算符间接验证。 我们后面会提到,可以用指针变量去访问实参数组中的每个元素。 【例8.11】定义一个函数voidselectsorting(inta[],intn)实现选择排序。 #include voidselectsorting(int[],intn); main() { intb[10]; inti; for(i=0;i<10;i++) scanf("%d",&b[i]); selectsorting(b,10); for(i=0;i<10;i++) printf("%d",b[i]); } voidselectsorting(inta[],intn) { inti,j; for(i=0;i<=n-2;i++) { /*找出剩余序列(即从a[i]到a[n-1])中值最小的数组元素的下标, 存储在变量min_index中*/ intmin_index=i;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第八章 函数 第八
![提示](https://static.bingdoc.com/images/bang_tan.gif)