C语言完整函数教程.ppt

上传人:小飞机 文档编号:5426301 上传时间:2023-07-05 格式:PPT 页数:128 大小:1.43MB
返回 下载 相关 举报
C语言完整函数教程.ppt_第1页
第1页 / 共128页
C语言完整函数教程.ppt_第2页
第2页 / 共128页
C语言完整函数教程.ppt_第3页
第3页 / 共128页
C语言完整函数教程.ppt_第4页
第4页 / 共128页
C语言完整函数教程.ppt_第5页
第5页 / 共128页
点击查看更多>>
资源描述

《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)函数原型可以放置在任何函数

26、之外,出现在该函数原型之后的所有函数都可以调用对应的函数;也可以放在某个函数中,此时只有该函数能够调用它。从程序设计风格考虑,最好是将函数原型集中在一起,放在主函数之前。(5)当被调用函数的函数定义出现在该函数调用之前时,可以省略函数原型。因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、类型和顺序。,5.2.4 函数的原型,/*square函数在main和fun中均可被调用*/float square(float);main()int fun()float square(float y)return(y*y);,main()/*square函数只能在main中被调用*/flo

27、at square(float);int fun()float square(float y)return(y*y);,/*函数定义*/float square(float y)return(y*y);main(),50,(6)函数原型、函数定义、函数调用要保持一致。和函数原型不匹配的函数调用会导致语法错误;函数原型和函数定义不一致,也会产生错误。(7)如果程序中没有包含函数原型,则编译器就会用第一次出现的该函数(函数定义或函数调用)来构造函数原型。默认情况下,编译器假定函数的返回类型为int类型,而对参数不作任何假定。,5.2.4 函数的原型,#includefloat square(flo

28、at y);/函数原型main()float x=2.5;printf(“%.2f”,square(x);/函数调用 system(pause);/*函数定义*/float square(float y)return(y*y);,51,(8)函数原型可以用来强制转换参数类型。在函数调用之前,和函数原型中的参数类型不完全一致的实参值会被转换为合适的类型。如:sqrt 的参数类型是double,进行如下调用printf(“%.3fn”,sqrt(4)时,在将4传递给sqrt之前先转换为double类型的值4.0;参数类型的转换有可能是低类型向高类型转换,也可能是高类型向低类型转换。高类型向低类型转

29、换可能会导致不正确的结果(如long类型向short类型的转换)。,5.2.4 函数的原型,52,5.1 子程序设计5.2 函数5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,53,5.3 头文件,对于一些通用的函数(如输入输出函数、数学函数等),可能在不同的程序中都会用到。为了使用这些函数,需要在程序中说明其函数原型。一种方式是在程序中逐个写出函数原型;double sqrt(double x);double fabs(double x);另一种方式是将这些函数原型集中在一起,形成.h头文件,然后在程序中直接包含这些头文件。#inc

30、lude,54,每一个标准库都有一个相应的头文件,文件扩展名为.h(如stdio.h,示例)。该头文件包含了该库中所有函数的原型以及这些函数所需的所有常量和数据类型的定义。程序员可以根据需要自己建立头文件,使用include命令可以把程序员定义的头文件包含到程序中,如:#include“square.h”注意:#include包含标准库的头文件#include“square.h”包含程序员自定义的头文件,5.3 头文件,55,5.1 子程序设计5.2 函数5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,56,例1、验证歌德巴赫猜想 任

31、一充分大的偶数,可以用两个素数之和表示,例如:4=2+26=3+3 10=3+7 10=5+5.9 8=1 9+7 9输入一个偶数,将其表示为两素数之和,并输出,5.4 函数应用举例,57,例1、验证歌德巴赫猜想,思路:偶数num是要分解的数,则 num=i+(num-i)其中i和(num-i)都得是素数因此可以对i可能的取值进行穷举。,58,例1、验证歌德巴赫猜想,main()int num;/*num:要判断的一个偶数*/int num1;/*num表示为两个素数num1和num-num1之和*/int count;/*计数输出个数,用于换行。*/printf(输入要验证的偶数:);sca

32、nf(%d,59,例1、验证歌德巴赫猜想,else/采用穷举法,将num分解为两个素数之和 count=0;for(num1=2;num1=num/2;num1+)if(isPrim(num1),60,5.4 函数应用举例,例2:设计一个函数,将十进制数转换成二进制、八进制和十六进制。然后在主函数中读入一个整数,调用函数,输出转换结果。算法思路:见C程序设计教程489490页,61,例2.进制转换,假设将十进制数57转换为二进制从右到左写出每列的位值,直到发现位值大于该十进制数的列。这样就先得到 位值:64 32 16 8 4 2 1然后去掉位值为64的列,得到:位值:32 16 8 4 2

33、1然后,从左至右进行。57除以32得商为1,余数为25,所以在32这列写下1,然后25除以16商为1,余数为9,所以在16这列写下1,位值:32 16 8 4 2 1 符号值:1 1 1 0 0 1 所以(57)10=(111001)2,62,例2.进制转换,假设将十进制数57转换为八进制从右到左写出每列的位值,直到发现位值大于该十进制数的列。这样就先得到 位值:64 8 1然后去掉位值为64的列,得到:位值:8 1然后,从左至右进行。57除以8得商为7,余数为1,所以在8这列写下1,然后1除以1商为1,余数为0,所以在1这列写下1.位值:8 1 符号值:7 1 所以(57)10=(71)8,

34、63,例2.进制转换,/*将num转换为base进制并输出*/void transfer(int num,int base)int p,k;p=1;while(p=num)/求p:p是base的x次幂,且p大于num p=p*base;p=p/base;/*循环求base进制数的各位*/while(p!=0)k=num/p;/*计算当前要输出的那个十进制数*/if(k=9)printf(%d,k);else printf(%c,k 10+A);num=num%p;p=p/base;,64,例3:掷骰子游戏(见C程序设计教程119页)1、rand()函数:产生一个0到RAND_MAX之间的整数,

35、使用时需要包含头文件。RAND_MAX 是在头文件中定义的符号常量,ANSI规定其不得小于32767。用于产生16之间的随机数:1+rand()%6,5.4 函数应用举例,65,每一次调用函数rand()时,0到RAND_MAX之间的每一个数字被选中的机会几乎均等(见书上120页图5-5)rand()所产生的随机数是伪随机数,反复调用rand()产生的一系列数似乎是随机的,但是每次执行程序所产生的序列则是重复的(重复运行120页图5-4的程序得到的结果是一样的)。,5.4 函数应用举例,66,2、srand(unsigned)函数如何实现真正的随机化:为函数rand设置随机数种子;每次执行程序

36、时,只要随机数种子不同,产生的随机数序列也将不同(见书上122页图5-6)。,让机器设置随机数种子:srand(time(NULL):通过time函数使计算机读取当前时间值(以秒为单位,如1099228431),并把该值设成随机数种子,这样可以避免用户自己输入随机数种子。,5.4 函数应用举例,67,例4、碰运气游戏(见C程序设计教程123页)游戏规则:投掷两个骰子,1、第一次投掷时,如果所得和为7或者11,则游戏者赢了;如果得到的和为2、3或者12,则游戏者输了;2、如果和为4、5、6、8、9或10,那么这个和就是游戏者的点数,要想赢的话,必须继续投掷骰子,直到取得自己的点数为止,但是,如果

37、投掷出了点数7,那么游戏者就输了。,5.4 函数应用举例,68,习题目的:见书上124页1、温习随机数的产生方法;2、switch结构、if-else结构、while结构综合运用;3、体会使用函数的好处(代码复用、降低代码书写难度、提高代码易读性);4、体会gameStatus变量对简化程序结构的作用;,5.4 函数应用举例,69,打印日历:输入年份和月份,输出该月日历。如下图所示:,5.4 函数应用举例,70,1.假设公元0001年年初到第year年年底的总天数为days天,则 daysyear*365+year/400+year/4-year/100分析如下:days=year*365 0

38、001年到year年闰年总年数 闰年条件:能被4整除但不能被100整除 或者 能被400整除。能被4整除但不能被100整除的年数:设0001年到year年年底 能被4整除的年数为x(则x=year/4)0001年到year年年底 能被4整除但不能被100整除的年数为 y,0001年到year年年底 能被4整除也能被100整除的年数为 z(则z=year/100,因为能被100整除则肯定能被4整除)则 y=x-z=year/4-year/100能被400整除的年数为:year/400故0001到year年内闰年总年数为:year/400+year/4-year/100,5.4 函数应用举例,71

39、,2.判断第days天是星期几:weekDay=days7(weekDay值为0,表示周日。WeekDay为16,分别表示周一到周六),5.4 函数应用举例,72,考试地点:上课教室 考试时间:第十周周一上午3、4节闭卷考试,手机关机。提供草稿纸,自己不要带。尽量隔开坐。,73,5.1 子程序设计5.2 函数5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,74,5.5 变量作用域,变量的基本属性:变量名、变量类型、变量值变量的其他属性:作用域(scope,程序中可引用该变量的区域)存储类别(storage class,变量存储在哪里)

40、存储期(storage duration,变量存活期)连接(linkage),75,5.5 变量作用域,变量作用域即可以引用该变量的程序段。C语言中变量可以在三种位置进行定义:函数内部的定义部分(即任何语句之前);函数内部的某一个复合语句内部;所有函数之外。变量定义的位置决定了变量的作用域。以上三种位置的变量分别对应于:函数作用域;块作用域;文件作用域。,在一个函数内部定义的变量称为内部变量或者局部变量。在所有函数之外定义的变量称为 外部变量或者全局变量。,76,若变量在函数内所有语句之前定义,则该变量具有函数作用域:只有在定义变量的函数内部才能使用这些变量。,变量作用域函数作用域,77,in

41、t f1(int a)/*函数f1*/int b,c;/*a,b,c作用域:仅限于函数f1()中*/main()int m,n;/*m,n作用域:仅限于函数main()中*/,变量作用域函数作用域,78,变量作用域函数作用域,1主函数main()与其它函数是平行关系。main()中定义的内部变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。2形参变量也是内部变量,属于被调用函数。3允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。,79,变量作用域块作用域,若变量在复合语句中定义,则其具有块作用域:只

42、在复合语句范围内才能引用该变量。允许函数定义部分定义的变量与该函数内部的复合语句中定义的变量同名。在复合语句执行时,函数定义部分定义的变量是“隐藏的”,直到复合语句结束。建议:尽量不要这么做。系统不会混淆,并不意味着人也不会混淆!,80,变量作用域块作用域,main()int x=5;printf(“local x in outer scope of main is%dn”,x);/复合语句中定义的变量x的作用域 int x=7;printf(“local x in inner scope of main is%dn”,x);printf(“local x in outer scope of

43、main is%dn”,x);,local x in outer scope of main is 5local x in inner scope of main is 7local x in outer scope of main is 5,81,若变量在函数外部定义,则该变量具有文件作用域:从变量的定义位置开始,到本文件结束为止的区域可以引用该变量。若该变量被定义成非静态外部变量,则其也能被其他文件引用(后面会讲到)。由于变量在函数外定义,此类变量称为外部变量。由于其在文件范围内可引用,所以又称全局变量。,变量作用域文件作用域,82,int area;int vs(int length,i

44、nt width,int height);main()int volumn,length,width,height;printf(“n input length,width and height:);scanf(“%d,%d,%d,例:输入长方体的长(l)、宽(w)、高(h),求长方体体积及侧面积之和。,83,(1)外部变量可以减少函数参数的使用,但会加强函数之间的数据联系,使这些函数依赖这些外部变量,因而使得这些函数的独立性降低(重用函数时必须要记得“带着”外部变量)。【示例】(2)由于无法限制各函数对外部变量的访问,可能会使外部变量被某些函数非法修改,当程序出错时不好检查。从模块化程序设计

45、的观点来看这是不利的,因此不是非用不可时,不要使用外部变量。(3)在同一源文件中,允许外部变量和内部变量同名。在内部变量的作用域内,外部变量将被屏蔽而不起作用。【示例】,变量作用域文件作用域,84,int num=5;/*定义外部变量num*/main()int num=6;/*定义内部变量num*/printf(“%d”,num);/*输出结果是6,外部变量num在 main函数中被屏蔽*/.,示例:内部变量屏蔽同名外部变量,变量作用域文件作用域,85,(3)外部变量的作用域是从定义点到本文件结束。如果文件中定义点之前的函数需要引用这些外部变量时,需要在函数内对被引用的外部变量进行说明。外部

46、变量说明的一般形式为:extern 数据类型 外部变量,外部变量2;【示例】【Next】,变量作用域文件作用域,86,函数1,函数2,外部变量,函数1先对外部变量进行了加工;然后函数2使用加工后的外部变量值;函数1 和函数2之间虽然没有调用关系,但通过外部变量建立起了联系;由于依赖于外部变量的存在,函数1 和函数2独立性差;,修改,读取,Return,变量作用域文件作用域,87,例:外部变量的定义与说明。int CalVolumn()extern int length,width,height;/*外部变量的说明*/return(length*width*height)/*使用外部变量*/in

47、t length=3,width=4,height=5;/*外部变量的定义*/main()printf(volumn=%d,CalVolumn();,Return,变量作用域文件作用域,注意:外部变量的定义和外部变量的说明是两回事。外部变量的定义,必须在所有的函数之外,且只能定义一次。而外部变量的说明,出现在所有要使用该外部变量的函数内。,88,5.1 子程序设计5.2 函数5.3 头文件5.4 函数应用举例5.5 变量作用域5.6 变量的存储类别5.7 内部函数和外部函数,提纲,89,在语言中,变量有以下四种存储类别:自动(auto)、寄存器(register)、静态(static)、外部(

48、extern)。变量的存储类别(storage class)和变量的作用域(scope)、连接(linkage)存在着一定联系。变量的存储类别决定着变量存储空间在哪里分配(栈区、静态存储区、寄存器),决定了变量的存储期。,5.6 变量的存储类别,90,5.6 变量的存储类别,局部变量的存储类别可以是:自动(auto),寄存器(register),静态(static)全局变量的存储类别可以是:静态(static),外部(extern)int solutions;/solutions是全局变量 main()int i;/i是局部变量 char ch;/ch是局部变量,91,变量的存储类别 auto

49、,若局部变量按以下形式定义,则其具有auto(自动)存储类别:auto 数据类型 变量表;/auto可写可不写1.存储期:存储空间在进入函数体或者复合语句体时在栈区分配,退出函数体或者复合语句体时被释放。2.作用域:块作用域或者函数作用域。3.连接:不能被其他文件中的函数访问。4.若定义而不初始化,则其值是不确定的。如果初始化,则赋初值操作是在函数调用或进入复合语句时进行的,且每次都要重新赋一次初值。,92,变量的存储类别 auto,main()int x=5;int y=7;,x和y是存储类别为auto的局部变量,main()auto int x=5;auto int y=7;,等价于,93

50、,一般情况下,变量的值都是存储在内存中的。为提高执行效率,语言允许将局部变量的值存放到寄存器中,这种变量称为寄存器变量。定义格式如下:register 数据类型 变量表;如:register int x=5;1.存储期:存储空间在进入函数体或者复合语句体时在寄存器分配,退出函数体或者复合语句体时被释放。2.作用域:块作用域或者函数作用域。3.连接:不能被其他文件中的函数访问。4.允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。现代编译系统一般自动分配寄存器,所以程序员说明的寄存器变量不起作用。,变量的存储类别 register,94,局部变量和全局变量均可以定义成具有static(静

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号