C语言完整函数教程.ppt
《C语言完整函数教程.ppt》由会员分享,可在线阅读,更多相关《C语言完整函数教程.ppt(128页珍藏版)》请在三一办公上搜索。
1、1,2,5.1 子程序设计5.2 函数5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,3,编写程序,求所有四位可逆素数,所谓可逆素数是这么一种素数,它的逆数也是素数。包含的主要功能:判断一个数是否素数。求一个整数的逆数。如1234的逆数是4321。,5.1 子程序设计,4,5.1 子程序设计,求可逆素数,本程序中判断素数的代码会出现两次;判断素数、求整数逆数这两个功能是独立的功能,且在多个程序中都有可能用到:求一个整数的逆数:该功能在判断一个整数是否回文数中也被用到;判断一个数是否素数:该功能在对整数进行素数分解中用到。,5,5.1
2、子程序设计,能否将完成上述独立功能的代码包装成一个单元,并且可以供其他代码来调用?-答案是可以使用子程序一.子程序的定义 子程序是封装并给以命名的一段程序代码,这段程序代码完成子程序所定义的功能,可供调用。封装:调用者只需要关心代码能完成什么功能,如何调用代码(即子程序接口),而不需要关心代码的内部实现。,6,判断素数的,子程序,调用,判断素数的,子程序,调用,计算逆数的,子程序,调用,5.1 子程序设计,子程序很重要的特点:调用者只需要关心子程序接口,不必了解子程序内部实现细节。,isPrim,reverse,可以设计子程序isPrim,用于判断一个整数是否是素数;子程序reverse,用于
3、计算一个整数的逆数;,7,5.1 子程序设计,二.子程序的控制和调用机制,通过子程序名进行调用;调用时需要传递一些供子程序计算和处理的数据(参数);子程序执行完成后需要返回处理结果。,8,判断素数的,子程序,调用,5.1 子程序设计,flag=isPrim(num),判断素数的,子程序,调用,flag=isPrim(reverseNum),子程序名,参数,返回值,9,5.1 子程序设计,三.引入子程序的目的 1.程序“复用”,避免在程序中使用重复代码;2.结构化程序设计的需要:自顶向下、逐步细化,将复杂问题分解为相对简单的子问题,这些子问题用子程序实现,从而提高主程序结构的清晰性和易读性。3.
4、使程序的调试和 维护变得更加容易。,10,四.子程序设计原则 高内聚:功能相对独立和完整;低耦合:与外界的关系尽量松散,不要太紧密,使其能方便地被重用;需要合理地设计子程序参数和子程序执行的局部环境 来达到以上目标。,5.1 子程序设计,五.子程序在C语言中的实现机制C语言中的函数机制,11,5.1 子程序设计5.2 函数5.2.1 函数5.2.2 函数的定义5.2.3 函数的调用5.2.4 函数原型5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,12,C语言中用函数实现子程序设计思想。较大的C语言应用程序,往往是由多个函数组成的(用
5、户自定义函数或标准库函数),每个函数完成明确的功能;每一个函数应该只完成单一的预定好的任务,并且函数名能有效地反映函数完成的任务;如果不能选择简洁的函数名,那可能函数完成的功能太多,建议拆分成几个较小的函数。C标准库提供了丰富的函数集,能够完成常用的数学计算、字符串操作、输入/输出等有用操作,程序员可以直接使用、从而减少工作量;,5.2.1 函数,13,5.1 子程序设计5.2 函数5.2.1 函数5.2.2 函数的定义5.2.3 函数的调用5.2.4 函数原型5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,14,5.2.2 函数的定
6、义,函数设计的要求:明确该函数的功能;定义该函数的接口(即函数头,包括函数名、参数和返回值)定义该函数的功能实现部分,15,5.2.2 函数的定义,函数定义的格式:返回值类型 函数名(参数列表)/*接口定义部分*/声明 语句,/*功能实现部分*/,函数定义:求x的y次方int power(int x,int y)int i,p=1;p=1;for(i=1;i=y;i+)p=p*x;return p;,1、函数名简洁、能反映出函数的功能。如:square、printf等。,3、返回值类型(1)指返回给函数调用者的结果的类型;(2)如果不指明返回值类型,编译器将假定返回值是int型(最好明确指定)
7、;(3)如果函数不返回任何值(即函数功能实现部分无return语句),则返回值类型定义成void。若返回值类型不是void,但又无return语句,则函数将返回一个不确定的值;,4、返回值与return语句(1)return语句的一般格式:return(返回值表达式);或 return 返回值表达式;(2)return语句的功能:返回调用函数,并将“返回值表达式”的值带给调用函数;(3)return语句中返回值表达式的类型要和返回值的类型说明一致。如果不一致,则以返回值类型为准(进行类型转换)。,2、参数列表(1)参数列表声明了在调用函数时函数所接收的参数,形式为:数据类型 参数1,数据类型
8、参数2(2)如果函数不接收任何参数,则参数列表定义为void;如 int print(void)(3)如果不列出参数的类型,编译器就假定其为int类型。但最好明确指定参数的类型,即使是int型,最好也明确定义。,16,5.2.2 函数的定义,练习1:设计一个函数IsLeapYear(n),用于判断n年是否是闰年。如果是,则返回1;否则返回0。n年是否是闰年的判断条件为:a)n能被4整除但不能被100整除;或b)n能被400整除。,【程序演示】,17,5.2.2 函数的定义,/*函数功能:判断n是否是闰年 参数:year:要判断的年份 返回值:若是闰年,返回1,否则返回0*/int isLeap
9、Year(int year)if(year%4=0,18,常见的程序设计错误:(1)把同一种类型的参数声明为类似于形式float x,y,而不是float x,float y;(2)在函数内部把函数参数再次定义成局部变量是一种语法错误;如:int sum(int x,int y)int x,y;/错误!return(x+y);,5.2.2 函数的定义,19,5.2.2 函数的定义,(3)不能在一个C函数的内部定义另一个函数;main()int sum(int x,int y)return(x+y);,不允许!,20,5.2.2 函数的定义,练习2:定义以下问题的函数头 设计一函数,求一个正整数
10、的长度;int length(int n)设计一函数,求三个整数中的最大值;int max(int n1,int n2,int n3),21,5.2.2 函数的定义,练习3:要求设计一个函数:isPrim(x)函数定义:isPrim(x)=1 当x 是素数;=0 当x 不是素数;,22,5.2.2 函数的定义,要判断的数通过参数传入,判断结果通过return语句返回,23,/*函数功能:判断一个正整数是否为素数.若是,则返回1;否则返回0。输入参数:n:要判断的整数。返回值:若n是素数,则返回值为1;否则返回值为0。*/int isPrim(int n)int i;/*不断判断n能否被i整除。
11、i的取值范围是2sqrt(n)*/int isPrim;/*isPrim=1:表示n是质数;isPrim=0:表示n不是质数*/i=2;isPrim=1;/*初始设定n是素数。在判断中一旦发现不是素数,则isPrim被修改成0。*/while(i=sqrt(n)/*返回*/,24,5.1 子程序设计5.2 函数5.2.1 函数5.2.2 函数的定义5.2.3 函数的调用5.2.4 函数原型5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,25,5.2.3 函数的调用,函数是一段封装的代码,能完成预定好的、独立的任务,能被其他函数所调用。
12、那么,如何调用一个函数?函数的调用和执行的实质是控制转移,调用函数时,将控制转到被调用的函数,被调函数执行结束时,则将控制转回主调函数,继续执行后续的操作。,26,int square(int);/*函数原型*/main()int x;for(x=1;x=10;x+)printf(“%4d”,square(2*x);int square(int y)/*函数定义*/return(y*y);,实参,形参,函数调用过程:给被调用函数分配存储空间;计算实际参数表达式的值;把实际参数的值按赋值转换规则转换成形式参数的类型。把转换后的实际参数(实参)的值送入形式参数(形参)中。运行调用函数中的语句;计算
13、返回值表达式的值,并转换成函数的结果类型;释放被调用函数占用的存储空间;带着转换后的值返回调用函数。,函数调用,函数原型的作用:是对被调用函数的接口声明,它告诉编译器函数返回的数据类型、函数所要接收的参数个数、参数类型和参数顺序,编译器用函数原型校验函数调用是否正确。函数调用:函数名(实参1,实参2,),27,5.2.3 函数的调用,int square(int);/*函数原型*/main()int x;for(x=1;x=10;x+)printf(“%4d”,square(2*x);int square(int y)/*函数定义*/return(y*y);,2000H,2002H,2005H
14、,2007H,2006H,2003H,2001H,x,存储空间,y,1,2,4,函数调用,28,5.2.3 函数的调用,#includemain()int i;for(i=1000;i=9999;i+)if(isPrim(i)=1)printf(%dt,i);return 0;int isPrim(int n)/略,输出4位正整数中的素数,等价于:for(i=1000;i=9999;i+)if(isPrim(i)printf(%dt,i);此种写法更接近于人惯用的表达方式,29,在语言中,可以用以下几种方式调用函数:对于有返回值的函数:(1)函数表达式。函数作为表达式的一个操作数,出现在表达式
15、中,函数返回值参与表达式的运算。如:i=2*max(x,y);if(isPrim(n)(2)函数实参。函数作为另一个函数调用的实际参数。这种情况是把该函数的返回值作为实参进行传送。如:printf(”the large number is%d”,max(x,y);对于无返回值的函数:(3)函数语句。C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。如:printf(”hellon”);,5.2.3 函数的调用,30,5.2.3 函数的调用,切记:实参的个数、类型和顺序,应该与形参个数、类型和顺序一致,才能正确地进行数据传递。实参可以是常量、变量、表达式、函数等
16、。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元(有例外,以后会讲到)。,31,5.2.3 函数的调用,实参和形参占用不同的内存单元,即使同名也互不影响。实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向传送给实参。不同函数中可以使用相同名称和类型的变量,它们占用不同的内存单元,互不影响。,32,5.2.3 函数的调用,如何确保能够逐层返回到上一级调用?为何不同的函数可以使用同名的参数和变量?进一步剖析函数的调用过程。,33,数据在内存中的存储,系
17、统区:用于存放系统软件和运行需要的数据,如操作系统。只要机器一运行,这部分空间就必须保留给系统软件使用。用户程序代码区:存放用户程序的代码。静态存储区:存放程序运行期间不释放的数据(静态局部变量,全局变量);栈区:存放程序运行期间会被释放的数据(非静态局部变量)以及活动的控制信息;堆区:用户可以在程序运行过程中根据需要动态地进行存储空间的分配,这样的分配在堆区进行;,5.2.3 函数的调用,用户数据区,int num;/全局变量void func(int n)static int m;/静态局部变量,34,一个类比:装东西的箩筐箩筐:一个存放东西的容器,框底封了口。装东西:东西从箩筐口入;取东
18、西:东西从箩筐口出,框顶的东西先被取出。即最先放入的东西最后才能取出;最后放入的东西最先取出(先进后出)。,5.2.3 函数的调用栈区简介,重点介绍和函数调用相关的栈区:,35,栈区一片存放用户数据的内存空间;一端“封”了口(栈底),一端“开”着口(栈顶);保存数据:数据只能从顶部(栈顶)进入;取数据:栈顶的数据先被取出,栈底的数据最后被取出。即数据是“先进后出”。数据的进入和退出均在栈顶进行。读数据:只能读取 栈顶的数据,5.2.3 函数的调用栈区简介,栈底,栈顶,36,5.2.3 函数的调用栈区简介,设计了一个位置指示top,用来指示当前的栈顶位置。通过top可以访问当前栈顶数据。数据的进
19、入和退出通过修改top的值来实现。,数据退出,数据进入,37,函数调用过程-开辟新的运行环境,int square(int);/*函数原型*/main()int x;for(x=1;x=10;x+)printf(“%4d”,square(x);int square(int y)/*函数定义*/return(y*y);,运行环境即指函数执行时需要的数据空间。需要哪些数据空间?,函数执行时需要的数据空间 1.生存期在本次函数执行过程中的数据对象,如形参、局部变量等;2.用以管理函数调用过程的信息。当函数A调用函数函数B时,函数A的运行被中断,当前机器的状态信息,如程序计数器(返回地址)、寄存器的值
20、等都必须保存,以便调用结束后,能准确返回到函数A并继续正确执行。,38,5.2.3 函数调用过程-开辟新的运行环境,为方便,引入一个术语:“函数的活动记录”。函数的活动记录是一段在栈区分配的连续的内存存储区,用以存放函数一次执行所需的数据。开辟新的运行环境即指在栈区的栈顶创建一个函数活动记录。释放本函数的运行环境即指从栈顶将活动记录释放。,被调用函数中的数据,现场信息,用于调用结束能正确返回,39,5.2.3 函数调用过程-开辟新的运行环境,int square(int);/*main()int x;for(x=1;x=10;x+)printf(“%4d”,square(x);int squa
21、re(int y)/*函数定义*/return(y*y);,为简化起见,假设square函数的活动记录只包含分配给形参y和返回地址的存储空间,40,int square(int);/*main()int x;for(x=1;x=3;x+)printf(“%4d”,square(x);int square(int y)/*函数定义*/return(y*y);,栈底,栈底,41,函数活动记录使用示例,main()A();B();,void A()C();,42,函数调用过程,总结如何确保能够逐层返回到上一级调用?函数A调用函数B,则在函数B的活动记录中记录了A的返回地址。返回前取出该地址,即能正确
22、返回。为何不同的函数可以使用同名的参数和变量?因为不同函数的活动记录占用不同的内存单元,程序运行时始终是从位于栈顶的活动记录中取形参和变量的值。,43,子程序参数传递两种方式:按值传递和按引用传递。按值传递:实参的值被复制并置入被调用子程序的形参中。此方式下不管在被调用子程序中怎样操作并改变形参的值,在主调程序中的实参的值都是安全的未发生变化的。,5.2.3 函数的调用,按值传递,按值传递(将实参的值传递给形参),实参,实参,形参,形参,44,5.2.3 函数的调用,按引用传递(函数调用时实参虽然写的是变量max,但实际传递的不是max的值,而是max的地址),主调程序(实参),子程序(形参)
23、,如何解决函数的多返回值问题?按引用传递:此时实参必须是变量,子程序调用时将实参的地址而不是实参的值置入被调子程序的形参中。被调子程序对形参的操作实际上是对主调程序中实参的操作,从而向主调程序传回函数处理结果。,45,5.2.3 函数的调用,注意:C语言中所有的调用都是传值调用,但是可以通过其他方式来实现函数的多返回值(即实参本身存放的就是某个变量的内存地址,将该地址传递给被调用函数后,被调用函数通过该地址来访问变量,将函数处理结果写入变量)。具体以后学习指针时讲解,46,5.1 子程序设计5.2 函数5.2.1 函数5.2.2 函数的定义5.2.3 函数的调用5.2.4 函数原型5.3 头文
24、件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,47,#includefloat square(float);/形参名可写可不写main()float x=2.5;printf(%.2f,square(x);system(pause);/*函数定义*/float square(float y)return(y*y);,5.2.4 函数的原型,编译到蓝色行时报错:conflicting types for square。错误原因:当自上而下对源程序编译时,编译到红色字体那一行,编译器会默认square(x)函数返回值类型是int型,从而和后面的fl
25、oat冲突。解决方法:在函数调用前使用函数原型对函数进行声明。,在文件stdio.h中已经给出了函数原型,思考:编译器为何不会提示printf未定义呢?,48,(1)C语言的原则(先声明、后使用);(2)函数原型的作用:函数原型是对被调用函数的接口声明,它告诉编译器函数返回的数据类型、函数所要接收的参数个数、参数类型和参数顺序,编译器用函数原型校验函数调用是否正确。(3)函数原型一般格式:返回值类型 函数名(数据类型 参数名1,数据类型 参数名2);注意:参数名可写可不写。,5.2.4 函数的原型,float square(float);/*函数原型*/,49,(4)函数原型可以放置在任何函数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 完整 函数 教程
链接地址:https://www.31ppt.com/p-5426301.html