C语言-函数与宏定义-省名师优质课赛课获奖课件市赛课一等奖课件_第1页
C语言-函数与宏定义-省名师优质课赛课获奖课件市赛课一等奖课件_第2页
C语言-函数与宏定义-省名师优质课赛课获奖课件市赛课一等奖课件_第3页
C语言-函数与宏定义-省名师优质课赛课获奖课件市赛课一等奖课件_第4页
C语言-函数与宏定义-省名师优质课赛课获奖课件市赛课一等奖课件_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

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

文档简介

第1章函数与宏定义

§1.1函数概念

§1.2变量作用域和存放类型

§1.3内部函数与外部函数

§1.4递归函数设计和调用

§1.5预处理

§1.6

综合范例

第1页2023/9/131§1.1函数概念

C语言中,函数可分为两类:一类是由系统定义标准函数,又称为库函数,其函数申明普通是放在系统include目录下以.h为后缀头文件中,如在程序中要用到某个库函数,必须在调用该函数之前用#include<头文件名>命令将库函数信息包含到本程序中。另一类函数是自定义函数第2页2023/9/132§1.1.1函数定义

[存放类型符][返回值类型符]函数名([形参说明表]){

函数语句体

}第3页2023/9/133说明:

1.[存放类型符]指是函数作用范围,它只有两种形式:static和extern。static说明函数只能作用于其所在源文件,用static说明函数又称为内部函数。extern说明函数可被其它源文件中函数调用,用extern说明函数,又称为外部函数。缺省情况为extern。2.[返回值类型符]指是函数体语句执行完成后,函数返回值类型,如int,float,char等等,若函数无返回值,则用空类型void来定义函数返回值。缺省情况为int型。第4页2023/9/1343.函数名由任何正当标识符组成。提议将函数名命名与函数内容有一定关系。4.[形参说明表]是一系列用逗号分开每个形参变量说明。如:intx,inty,intz这表示形参变量有三个:x,y,z。它们类型都是int型。

5.函数语句体是放在一对花括号{}中,由局部数据类型描述和功效实现两部分组成。第5页2023/9/1356.函数返回语句形式有以下两种:①函数无返回值情况:return;或者什么也不写②函数有返回值情况:return(表示式值);在第②种情况下要注意“表示式值”类型必须与函数返回值类型相一致。比如:求两个任意整数绝对值和,用函数abs_sum()实现。/*直接调用库函数来计算m和n绝对值*/intabs_sum(intm,intn){return(abs(m)+abs(n));

}/*函数abs()是在头文件math.h中申明*/第6页2023/9/136函数定义以下:intabs_sum(intm,intn){if(m<0)m=-m;if(n<0)n=-n;return(m+n);}§1.1.2函数申明和调用

1.函数申明函数申明普通形式:[存放类型符][返回值类型符]函数名([形参说明表]);如:intabs_sun(intm,intn);第7页2023/9/1372.函数调用函数调用是经过函数调用语句来实现,分两种形式:①无返回值情况:函数名([实参表]);②有返回值情况:变量名=函数名([实参表]);该变量名类型必须与函数返回值类型相同。函数调用时都会去执行函数语句中内容,函数执行完成后,回到函数调用处,继续执行下面语句。第8页2023/9/138§1.1.3函数传值方式

函数传值方式:

采取实参表将每一个实参值对应地传递给每一个形参变量,形参变量在接收到实参表传过来值时,会在内存暂时开辟新空间,以保留形参变量值,当函数执行完成时,这些暂时开辟内存空间会被释放,而且形参值在函数中不论是否发生改变,都不会影响到实参变量值改变,这就是函数传值方式。自定义函数在程序中使用次序有两种形式:①先进行函数申明,再进行函数调用,函数定义放在函数调用之后。函数申明在函数调用之前。②函数定义放在函数调用之前。第9页2023/9/139【例1-1】编程序,经过调用函数abs_sum(),求任意两个整数绝对值和。/*exam1_1.c调用函数求两整数绝对值和*/#include<stdio.h>intabs_sum(intm,intn);main(){ intx,y,z; scanf("%d%d",&x,&y); z=abs_sum(x,y); printf("sumis%d",z);}intabs_sum(intm,intn){ if(m<0) m=-m; if(n<0) n=-n; returnm+n;}程序运行结果:712

sumis19第10页2023/9/1310用传值方式调用函数时,实参也能够是函数调用语句

【例1-2】求任意三个数绝对值和。/*exam1_2.c调用函数求三个整数绝对值和*/#include<stdio.h>intabs_sum(intm,intn);main(){ intx,y,z,sum; scanf("%d%d%d",&x,&y,&z); sum=abs_sum(abs_sum(x,y),z); printf("sumis%d",sum);}intabs_sum(intm,intn){ if(m<0) m=-m; if(n<0) n=-n; returnm+n;}程序运行结果:7125

sumis24第11页2023/9/1311注意:对于有返回值函数,调用时若没有把它赋给某个变量,依然是能够,只是函数返回值有可能会被丢失。【例1-3】求任意两数乘积。自定义一个函数mul(),用于求两数乘积,程序:/*exam1_3.c求两个数乘积*/#include<stdio.h>floatmul(floata,floatb);main(){ floatx,y,z; scanf("%f%f",&x,&y); z=mul(x,y);/*①*/ x=x+10; y=y-10; mul(x,y);/*②*/第12页2023/9/1312

x=x*2; y=y*2; printf("z=%f,mul(%f,%f)=%f\n",z,x,y,mul(x,y));/*③*

/}floatmul(floata,floatb){ returna*b;}程序运行结果:56

z=30.000000,mul(30.000000,-8.000000)=-240.000000第13页2023/9/1313程序说明:注释①处调用函数后返回值赋给变量z。注释②处调用函数后返回值没有赋给任何变量,函数返回值被丢失。注释③处调用函数后返回值成为了printf()函数参数。第14页2023/9/1314§1.2变量作用域和存放类型

1.变量作用域

变量作用域:指是变量有效范围,针对变量不一样作用域,可把变量分为局部变量和全局变量。局部变量:在函数内部或某个控制块内部定义变量为局部变量,局部变量有效范围只限于本函数内部,退出函数,该变量自动失效。全局变量:在函数外面定义变量称为全局变量,全局变量作用域是从该变量定义位置开始,直到源文件结束。在同一文件中全部函数都能够引用全局变量。

第15页2023/9/1315局部变量和全局变量作用域如图所表示:第16页2023/9/1316【例1-4】变量作用域应用举例,阅读下面程序,注意区分局部变量和全局变量作用域。/*exam9_4.c变量作用域举例*/#include<stdio.h>voida(void);voidb(void);voidc(void);intx=1;main(){ intx=5; printf("localxinouterscopeofmainis%d\n",x);第17页2023/9/1317 {

intx=7; printf("localxininnerscopeofmainis%d\n",x); } printf("localxinouterscopeofmainis%d\n",x); a(); b(); c(); a(); b(); c();前三次输出结果:localxinouterscopeofmainis5localxininnerscopeofmainis7localxinouterscopeofmainis5第18页2023/9/1318

printf("localxinmainis%d\n",x); getchar(); return0;}voida(void){ intx=25; printf("\nlocalxinais%dafterenteringa\n",x); ++x; printf("localxinais%dbeforeexitinga\n",x);}第19页2023/9/1319voidb(void){ staticintx=50; printf("\nlocalstaticxis%donenteringb\n",x); ++x; printf("localstaticxis%donexitingb\n",x);}voidc(void){ printf("\nglobalxis%donenteringc\n",x); x*=10; printf("globalxis%donexitingc\n",x);}第20页2023/9/1320程序运行结果:

后6次函数调用localxinais25afterenteringalocalxinais26beforeexitinga

localstaticxis50onenteringblocalstaticxis51onexitingb

globalxis1onenteringcglobalxis10onexitingc

localxinais25afterenteringalocalxinais26beforeexitinga

localstaticxis51onenteringblocalstaticxis52onexitingbglobalxis10onenteringcglobalxis100onexitingc最终一次输出:localxinmainis5第21页2023/9/13212.变量存放类型变量存放类型:指是变量存放属性,它说明变量占用存放空间区域。在内存中,供用户使用存放区由程序区、静态存放区和动态存放区三部分组成。变量存放类型有四种:auto型、register型、static型和extern型。auto型变量存放在内存动态存放区。register型变量保留在存放器中。static型变量和extern型变量存放在静态存放器。第22页2023/9/1322局部变量存放类型缺省值为auto型。全局变量存放类型缺省值为extern型。auto型变量和register型变量只用于定义局部变量。static型变量即可定义成局部变量,又可定义成全局变量。【例1-5】设计一个函数:longfac(intn),可用来计算1~5阶乘。分析:可在函数中定义一个static型变量,用来保留上次计算结果。第23页2023/9/1323/*exam1_5.c用static型变量保留上次阶乘值*/#include<stdio.h>longfac(intn){ staticintf=1; f=f*n; returnf;}main(){ inti; for(i=1;i<=5;i++) printf("%d!=%ld\n",i,fac(i));}程序运行结果:1!=12!=23!=64!=245!=120局部变量f被定义成static型,所以,它只在该函数第1次被调用时候初始化其值为1,以后再调用该函数时,不再进行初始化,而是使用上一次调用值。

第24页2023/9/1324§1.3内部函数与外部函数

1.内部函数若函数存放类型为static型,则称其为内部函数或称静态函数,它表示在同一个程序中(由多个源文件组成),该函数只能在一个文件中存在,在其它文件中不可使用。如:staticintfun-name();内部函数只能被其所在源文件调用。2.外部函数若函数存放类型定义为extern型,则称其为外部函数,它表示该函数能被其它源文件调用。函数缺省存放类型为extern型。注意:在需要用到外部函数文件中,其函数申明必须用extern进行说明。第25页2023/9/1325比如:有两个源文件file1.c和file2.c以下所表示:/*file1.c调用外部函数*/#include<stdio.h>intmod(inta,intb);externintadd(intm,intn);/*外部函数申明*/main(){intx,y,result;scanf(“%d%d”,&x,&y);result=add(x,y);/*调用外部函数*/if(result>0)result=result-mod(x,y);printf(“result=%d\n”,result);}第26页2023/9/1326intmod(inta,intb){return(a%d);}/*file2.c外部函数*/externintadd(intm,intn){return(m+n);}说明:1.在文件1(file1.c)中函数申明:

intmod(inta,intb);实际上相当于:externintmod(inta,intb);第27页2023/9/13272.在文件2(file2.c)中函数定义:

externintadd(intm,intn){return(m+n);}实际上相当于:intadd(intm,intn){return(m+n);}3.由多个源文件组成一个程序时,main()函数只能出现在一个源文件中。第28页2023/9/13284.多个源文件连接方式有三种:①将各源文件分别编译成目标文件,得到多个目标文件(.obj后缀),然后用连接命令(tlink)把多个.obj文件连接起来,在Turboc上用以下命令:

tlinkfile1.obj+file2.obj+…+filen.obj生成一个file1.exe可执行文件。②建立项目文件(.prj后缀),详细操作可参阅各种C编译手册。③使用文件包含命令。第29页2023/9/1329§1.4递归函数设计和调用

C语言中一个函数中语句能够是对另一个函数调用。函数嵌套调用图例:调用过程按图中箭头所表示方向和次序进行,属于一个线性调用关系,每次调用后,最终返回到原调用点,继续执行以下语句。第30页2023/9/1330C语言中还允许在函数中调用本身,或函数之间相互调用,这种调用方式称之为递归。递归又分为直接递归调用和间接递归调用。直接递归调用;函数直接调用本身。间接递归调用:函数相互调用对方。直接递归:inttemp(intx){inty,z;……z=temp(y);……}第31页2023/9/1331间接递归:显然,递归有可能陷入无限递归状态,最终造成错误发生。所以,设计一个递归问题必须具备两个条件:1.后一部分与原始问题类似。2.后一问题是原始问题简化。第32页2023/9/1332【例1-6】编程,从键盘输入一个正整数n,求n!。n!数字表示式为:n!=定义一个求n!函数:longfac(intn)longfac(intn){longresult;if(n==0||n==1)result=1;elseresult=n*fac(n-1);return(result);}第33页2023/9/1333完整程序以下:/*exam1_6.c用递归法求n!*/#include<stdio.h>longfac(intn){ longresult; if(n==0||n==1) result=1; else result=n*fac(n-1); returnresult;}main(){ intx; longf;第34页2023/9/1334

scanf("%d",&x); if(x<=0) printf("Yourinputiswrong!\n"); else { f=fac(x); printf("%d!=%ld\n",x,f); }}程序运行结果:6

6!=720第35页2023/9/1335【例1-7】

求Fibonacci数列第i项值。Fibonacci数列:0,1,1,2,3,5,8,13,21,…其数字表示式为:

fibonacci(0)=0fibonacci(1)=1fibonacci(n)=fibonacci(n-1)+fibonacci(n-2)(n>1)设计一个函数:longfibonacci(intn)用于计算数列中第n项值,第36页2023/9/1336程序以下所表示:/*exam1_7.c求第n项Fibonacci数列值*/#include<stdio.h>longfibonacci(intn);main(){ intx=0; longresult; do { result=fibonacci(x); printf("fibonacci(%d)=%ld\n",x,result); scanf("%d",&x); }while(x!=-1);}第37页2023/9/1337longfibonacci(intn){ if(n==0||n==1) returnn; else returnfibonacci(n-1)+fibonacci(n-2);}程序运行结果:fibonacci(0)=03

fibonacci(3)=24

fibonacci(4)=36

第38页2023/9/1338以x=4为例,下列图说明了fibonacci函数是怎样计算fibonacci(4)。图中把fibonacci简写成f。第39页2023/9/1339

“编译预处理”是C与其它高级语言一个主要区分。它们主要是:

宏定义文件包含条件编译

1.5预处理第40页1)不带参数宏定义

用指定标识符(宏名)代表一串字符。

#define宏名字符串1.5.1宏定义例求正圆锥体底周长、底面积和它体积。#definePI3.1415926/*宏名PI用大写,行末无分号*/main(){floatl,s,r,v;scanf("%f",&r);l=2.0*PI*r;s=PI*r*r;v=4.0/3*PI*r*r*r;printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);getch();}第41页

进行宏定义时,能够引用已定义宏名,层层置换。

对程序中用双引号括起来字符串,即使与宏名相同,也不会被置换。

宏名有效范围为该宏定义命令之后至根源文件结束。通常,宏定义命令普通写在文件开头或函数之前作为该文件一部分。

能够用#undef

命令终止宏定义作用域。如:

#defineG9.8

main()

{

}

#undefG

floatf()

G作用范围第42页2.带参数宏定义语句形式:

#define宏名(形参表)字符串注意:字符串应包含形参表中参数例#definePI3.1415926#defineS(r)PI*r*rmain(){floata,area;a=3.6;area=S(a);/*area=3.1415926*a*a,但不会置换a为3.6*/printf("r=%f\narea=%f\n",a,area);getch();}第43页

若将area=S(a)

改写成area=S(a+2),将置换为:

area=PI

a+2

a+2,而不是:area=PI

(a+2)

(a+2)。若要到达后者,则应将宏定义命令改写为:

#defineS(r)PI

(r)

(r)

宏名与括号之间不得有空格,因为宏名与表示式之间分隔符为空格。假如用#defineS(r)PI

r

r

话,则被置换为area=(r)PI

r

r

(a)

宏展开并不进行值传递,即不求表示式值,也没有“返回值”概念。

宏不存在类型问题,宏名无类型,参数也无类型,表示式能够是任何类型。第44页注:这里t展开后为t=(a+b)>(c+d)?(a+b):(c+d)

假如第一行写成:#defineMAX(x,y)x>y?x:y则这里t展开后为t=a+b>c+d?a+b:c+d

因为置换展开是用“表示式”对等置换“形参表”中参数。

定义带参数宏,能够实现一些简单函数功效。如: #defineMAX(x,y)(x)>(y)?(x):(y)

main() {inta,b,c,t;

t=MAX(a+b,c+d);

}第45页1.5.2“文件包含”

#include

命令实现一个文件包含另一个文件。语句形式:#include“文件名”例#include"stdio.h"#defineN2#defineMN+1#defineNUM(M+1)*M/2main(){inti,n=0;for(i=1;i<=NUM;i++){n++;printf("%2d",n);}getch();}输出结果:12345678第46页

一个include命令只能指定一个被包含文件,假如要包含n个文件,则要用n个include命令。

NUM被代换展开后为:(2+1+1)

2+1/2#include命令中,文件名既可用双引“”号(推荐),也可用尖括号<>括起来。<>表示被包含在标准目录中(include).“”表示被包含文件在指定目录中,若只有文件名不带路径,则在当前目录中,若找不到,再到标准目录中找。包含文件名能够是.c源文件或.头文件,如#include<stdio.h>#include“myhead.h”#include“D:\myexam\myfile.c”第47页

条件编译

语句形式:1.#ifdef宏名 程序段1 [#else

程序段2] #endif

作用:假如宏名已定义,则编译“程序段1”,不然编译“程序段2”。所谓“宏名已定义”是不论“宏名”定义为何内容。

条件编译作用:缩短编译时间,降低目标程序长度。第48页

作用:假如宏名未定义,则编译“程序段1”,不然编译“程序段2”。3.#if表示式 程序段1 [#else

程序段2] #endif

作用:当“表示式”值为非0,则编译“程序段1”,不然编译“程序段2”。2.#ifndef宏名

温馨提示

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

最新文档

评论

0/150

提交评论