资源描述
Edit Master title,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,C,程序设计(第三版),江苏大学 计算机科学与通信工程学院,29,C,程序设计(第三版),江苏大学 计算机科学与通信工程学院,90,Edit Master title,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,第八章,函数,第八章函数,主要内容,8.1,概述,8.2,函数定义的一般形式,8.3,函数参数和函数的值,8.4,函数的调用,8.5,函数的嵌套调用,8.6,函数的递归调用,8.7,数组作为函数参数,8.8,局部变量和全局变量,8.9,变量的存储类别,8.10,内部函数和外部函数,主要内容 8.1 概述,8.1,概述,一个程序可由一个主函数和若干个其他函数构成。一个较大的程序可分为若干个程序模块,每一个模块用来实现一个特定的功能。在高级语言中用子程序实现模块的功能。子程序由函数来完成。,函数间的调用关系,:,由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。,思考:主函数可以被其它函数调用吗?,8.1 概述 一个程序可由一个主函数和若干个其他,C语言入门学习-C第8章-函数课件,例,8.1,先举一个函数调用的简单例子,# include ,void main(),void printstar();,/*,对,printstar,函数声明*,/,void print_message();,/*,对,print_message,函数声明*,/,printstar();,*调用,printstar,函数*,print_message();,/*,调用,print_message,函数*,/,printstar();,*调用,printstar,函数*,/,例8.1先举一个函数调用的简单例子,void printstar(),*定义,printstar,函数*,printf(* * * * * * * * * * * * * * * *n);,void print_message(),*定义,print_message,函数*,printf(How do you do!n);,运行情况如下:,* * * * * * * * * * * * * * * *,How do you do!,* * * * * * * * * * * * * * * *,void printstar() *定义printstar,说明:,(1),一个程序由一个或多个程序模块组成,对于较大的程序,通常将程序内容分别放在若干个源文件中,再由若干源程序文件组成一个,C,程序。这样便于分别编写、分别编译,提高调试效率。一个源程序文件可以为多个,C,程序公用。,说明:,(2),一个源程序文件由一个或多个函数以及其他有关内容(如命令行、数据定义等)组成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不是以函数为单位进行编译的。,(3),程序的执行是从,main,函数开始的,,如果在,main,函数中调用其他函数,在调用后流程返回到,main,函数,,在,main,函数中结束整个程序的运行,。,(2) 一个源程序文件由一个或多个函数以及其他有关内容(如命,(4),所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。一个函数并不从属于另一函数,即函数不能嵌套定义。函数间可以互相调用,但不能调用,main,函数。,main,函数是系统调用的。,(4)所有函数都是平行的,即在定义函数时是分别进行的,是互相,(5),从用户使用的角度看,函数有两种:,标准函数,即库函数。这是由系统提供的,用户不必自己定义这些函数,可以直接使用它们。不同的,C,系统提供的库函数的数量和功能会有一些不同,但许多基本的函数是共同的。,用户自己定义的函数。用以解决用户的专门需要。,(5)从用户使用的角度看,函数有两种:,(6),从函数的形式看,函数分两类:,无参函数。无参函数一般用来执行指定的一组操作。在调用无参函数时,主调函数不向被调用函数传递数据。,有参函数。主调函数在调用被调用函数时,通过参数向被调用函数传递数据。,(6) 从函数的形式看,函数分两类:,8.,函数定义的一般形式,8.2.1,无参函数的定义一般形式,定义无参函数的一般形式为,:,类型标识符,函数名,(),声明部分,语句部分,8.函数定义的一般形式 8.2.1 无参函数的定义一般形,8.2.2,有参函数定义的一般形式,定义有参函数的一般形式为,:,类型标识符,函数名,(形式参数表列),声明部分,语句部分,例如:, (,int,,,int,), ;,/ *,函数体中的声明部分*,?;,return,();,8.2.2 有参函数定义的一般形式 定义有参函数的一般形,8.2.3,空函数,定义空函数的一般形式为,:,类型标识符,函数名,(), ,例如:,(), ,主调函数调用空函数时,只表明这里要调用一个函数,但函数本身什么工作也不做。,8.2.3 空函数 定义空函数的一般形式为:主调函数调用空,8.,函数参数和函数的值,8.,.,形式参数和实际参数,形式参数:,函数名后面括号中的变量名称为,“,形式参数,”,(简称,“,形参,”,)。,实际参数:,主调函数中调用一个函数时,函数名后面括号中的参数,(,可以是一个表达式,),称为,“,实际参数,”,(简称,“,实参,”,)。,函数返回值:,return,后面的括号中的值作为函数带回的值(称,函数返回值,)。,8.函数参数和函数的值 8.形式参数和实际参数,主调函数和被调用函数之间有数据传递的关系。在不同的函数之间传递数据,可以使用的方法有:,参数:通过形式参数和实际参数,返回值:用,return,语句返回计算结果,全局变量:外部变量,主调函数和被调用函数之间有数据传递的关系。在不同,例,8.,调用函数时的数据传递,#include ,void main(), int max(int x,int y);,/*,对函数的声明 *,/,int a,b,c;,scanf(%d,%d,c=max(a,b);,printf(Max is %d,c);,例8.调用函数时的数据传递,int max(int x,int y)/*,定义有参函数,max */,int z;,z=xy?x:y;,return(z);,运行情况如下:,,,int max(int x,int y)/*定义有参函数ma,通过函数调用,可使两个函数中的数据发生联系。,通过函数调用,可使两个函数中的数据发生联系。,关于形参与实参的说明:,(,1,),在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数,max,中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。,(,2,),实参可以是常量、变量或表达式,,例如:,max,(,);,但要求它们有确定的值。在调用时将实参的值赋给形参。,关于形参与实参的说明:(1) 在定义函数中指定的形参,在未出,(,3,),在被定义的函数中,必须指定形参的类型。,(,4,),实参与形参的类型应相同或赋值兼容。,(,5,),值传递,:,实参向形参的数据传递是单向“值传递”,只能由实参传给形参,,而不能由形参传回来给实参。,在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。,(3)在被定义的函数中,必须指定形参的类型。(4)实参与形参,调试程序理解值传递,void fun(int a,int b,int c), a=456;b=567;c=678;,main(),int x=10,y=20,z=30;,fun (x,y,z);,printf(%d,%d,%dn,z,y,x);,调试程序理解值传递void fun(int a,int b,8.3.2,函数的返回值,函数的返回值,是通过函数调用使主调函数得到的确定值。,例如,:,例,8.,中,,max,(,)的值是,,max,(,)的值是,5,。赋值语句将这个函数值赋给变量。,8.3.2 函数的返回值 函数的返回值是通过函数调用使,说明:,(,1,)函数的返回值是通过函数中的,return,语句获得的。,一个函数中可以有一个以上的,return,语句,执行到哪一个,return,语句,哪一个语句起作用。,return,语句后面的括弧也可以不要,例如,:,“return,;”,等价于 “,return,();”,return,后面的值可以是一个表达式。,例如,:,(,int,,,int,),return,(,?,:,);,说明:,(,2,)函数的返回值应当属于某一个确定的类型,,在定义函数时指定函数返回值的类型。,例如,:,下面是,3,个函数的首行:,int,max,(,float,,,float,),/*,函数值为整型 *,/,char,letter,(,char c1,,,char c2,),/*,函数值为字符型 *,/,double,min,(,int,,,int,),/*,函数值为双精度型,*,/,注意:,凡不加类型说明的函数,自动按整型处理。,(2)函数的返回值应当属于某一个确定的类型,在定义函数时指定,(,3,)在定义函数时指定的函数类型一般应该和,return,语句中的表达式类型一致。,如果函数值的类型和,return,语句中表达式的值不一致,则以函数类型为准。,对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。,例,8.3,(,4,)对于不带回值的函数,应当用“,void”,定义函数为“无类型”(或称“空类型”)。此时在函数体中不得出现,return,语句。,(3)在定义函数时指定的函数类型一般应该和return语句中,概念理解,下面函数的类型是,。,ff(float x),printf(“%dn”,x*x);,A.,与形参,x,的类型相同,B.void,类型,C.int,类型,D.,无法确定,在一个,C,语言程序中,。,A.main,函数必须出现在所有函数之前,B.main,函数可以在任何地方出现,C.main,函数必须出现在所有函数之后,D. main,函数必须出现在固定位置,下列关于,return,语句的说法,正确的是,。,A.,必须在每个函数中都出现,B.,只能在除主函数之外的函数中出现一次,C.,可以在同一个函数中多次出现,D.,在主函数和其他函数中都可以出现,概念理解下面函数的类型是 。,例,8., 返回值类型与函数类型不同,#include ,void main(),int max(float x,float y);,float a,b;,int c;,scanf(%f,%f,c=max(a,b);,printf(Max is %dn,c);,int max(float x,float y), float z;,z=xy?x:y;,return(z);,运行情况如下:,, ,Max is,例 8. 返回值类型与函数类型不同运行情况如下:,8., 函数的调用,8.,.1,函数调用的一般形式,函数调用的一般形式为,:,函数名(实参表列),说明,:,(,1,),如果是调用无参函数,则,“,实参表列,”,可以没有,但括弧不能省略。,8. 函数的调用 8.1 函数调用的一般形式函数调,(,3,),如果实参表列包括多个实参,对实参求值的顺序并不是确定的,有的系统按自左至右顺序求实参的值,有的系统则按自右至左顺序。,只要理解,(,2,),如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相等,类型应匹配。实参与形参按顺序对应,一一传递数据。,(3)如果实参表列包括多个实参,对实参求值的顺序并不是确定的,8.4.2,函数调用的方式,函数语句,把函数调用作为一个语句。这时不要求函数带回值,只要求函数完成一定的操作。,函数表达式,函数出现在一个表达式中,这种表达式称为,函数表达式,。这时要求函数带回一个确定的值以参加表达式的运算。例如,:,*(,);,按函数在程序中出现的位置来分,可以有以下三种函数调用方式:,8.4.2 函数调用的方式函数语句函数表达式,函数参数,函数调用作为一个函数的实参。,例如,:,m = max (a ,max ( b , c ),) ;,其中,max ( b , c ),是一次函数调用,它的值作为,max,另一次调用的实参。,m,的值是,a,、,b,、,c,三者中的最大者。,函数调用语句“,f(e1,e2),(e3,e4,e5);,”中参数的个数是,。,A.1 B.2 C.4 D.5,函数参数,8.4.3,对被调用函数的声明和函数原型,在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢 ?,1.,首先被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)。但光有这一条件还不够。,8.4.3 对被调用函数的声明和函数原型在一个函数中调用另一,3.,如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面,应该在主调函数中对被调用的函数作声明。,2.,如果使用库函数,还应该在本文件开头用,#include,命令将调用有关库函数时所需用到的信息“包含”到本文件中来。,3.如果使用用户自己定义的函数,而该函数的位置在调用它的函数,函数原型的一般形式为,:,1.,函数类型 函数名,(,参数类型,1,,参数类型,2),;,2.,函数类型 函数名,(,参数类型,1,,参数名,1,,参数类型,2,,参数名,2),;,声明的作用是把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。,函数原型的一般形式为: 声明的作用是把函数名、函数参数,注意:,函数的,“,定义,”,和,“,声明,”,的区别:,函数的定义是指对函数功能的确立,包括指定函数名,函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。,函数的声明的作用则是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。,注意:,例,8., 对被调用的函数作声明,#include,void main(),float add(float x,float y);,/*,对被调用函数,add,的声明*,/,float a,b,c;,scanf(%f,%f,c=add(a,b);,printf(sum is %f n,c);,float add(float x,float y) /*,函数首部*,/, float z; /*,函数体 *,/,z=x+y;,return(z);,例8. 对被调用的函数作声明,习题讲解,编写函数:任意输入一个整数,判断这个整数是否素数,如果是素数返回,1,,否则返回,0,。,编写函数:任意一个整数,返回这个整数的因子之和。,编写函数:任意一个整数,返回这个整数的各个位上的数字之和。,习题讲解编写函数:任意输入一个整数,判断这个整数是否素数,如,8., 函数的嵌套调用,8. 函数的嵌套调用,例,8., 用弦截法求方程,f(x)=x3-5x2+16x-80=0,的根,例 8. 用弦截法求方程,1.,取两个不同点,x1,x2,如果,f(x1),和,f(x2),符号相反,则,(x1,x2),区间内必有一个根。如果,f(x1),与,f(x2),同符号,则应改变,x1,x2,直到,f(x1),、,f(x2),异号为止。注意,x1,、,x2,的值不应差太大,以保证,(x1,x2),区间内只有一个根。,2.,连接,(x1,f(x1),和,(x2,f(x2),两点,此线,(,即弦,),交,x,轴于,x,。,方法:,1. 取两个不同点x1,x2,如果f(x1)和f(x2)符号,3.,若,f(x),与,f(x1),同符号,则根必在,(x,x2),区间内,此时将,x,作为新的,x1,。如果,f(x),与,f(x2),同符号,则表示根在,(x1,x),区间内,将,x,作为新的,x2,。,4.,重复步骤,(2),和,(3) ,直到 ,f(x),为止, ,为一个很小的数,例如,10,-6,此时认为,f(x)0,。,3. 若f(x)与f(x1)同符号,则根必在(x,x2)区间,实现各部分功能的几个函数,:,1.,用函数,f(x),代表,x,的函数,:x,3,-5x,2,+16x-80,。,2.,用函数调用,xpoint (x1,x2),来求,(x1,f(x1),和,(x2,f(x2),的连线与,x,轴的交点,x,的坐标。,3.,用函数调用,root (x1,x2),来求,(x1,x2),区间的,那个实根。显然,执行,root,函数过程中要用到函,数,xpoint,而执行,xpoint,函数过程中要用,到,f,函数。,实现各部分功能的几个函数:1. 用函数f(x)代表x的函数:,C语言入门学习-C第8章-函数课件,8.6,函数的递归调用,在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。,语言的特点之一就在于允许函数的递归调用。,例如:,int f ( int,), ,;,();,return,(*);,8.6 函数的递归调用 在调用一个函数的过程中又出现直接或,例,8.,用递归方法求!,求!也可以用递归方法,即!等于!,,而!,!。,因此:,f(n)=n,!可用下面的递归公式表示:,f(n)=f(n-1)*n,实现递归(函数调用自己)。,写程序思想方法:,如果(,)!,否则,(),时,n,!,=,()!,int fun(int n),int f;,if(n=0|n=1) f=1;,else f=n*fun(n-1);,return f;,例8.用递归方法求! 求!也可以用递归方法,即!等于,习题讲解,以下程序的运行结果是,#include,main(),int fun();,fun(567);,fun(int n),if(n10)fun(n/10);,printf(,%d,n%10);,函数,sum(int n),用递归的方法完成计算,习题讲解以下程序的运行结果是 函数sum(in,例,8.9 Hanoi,(汉诺塔)问题,:,由上面的分析可知:将个盘子从座移到座可以分解为以下,3,个步骤:,1.,将上个盘借助座先移到座上。,2.,把座上剩下的一个盘移到座上。,3.,将个盘从座借助于座移到座上。,例8.9 Hanoi(汉诺塔)问题:由上面的分析可知:将个,8.,数组作为函数参数,8.7.1,数组元素作函数实参,由于实参可以是表达式,而数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作实参一样,是单向传递,即,“,值传送,”,方式。,8.数组作为函数参数 8.7.1 数组元素作函数实参,以下程序运行后的输出结果是,。,int f(int a),return a%2;,main(),int s8=1,3,5,2,4,6,i,d=0;,for(i=0; f(si); i+) d+=si;,printf(%dn,d);,例,8.10,,同学自己看书理解,以下程序运行后的输出结果是 。,8.7.2,数组名作函数参数,用数组名作函数参数时,此时形参应当用数组名或用,指针变量(后面章节学习),。,例,8.11,有一个一维数组,score,,内放,10,个学生成绩,求平均成绩。,8.7.2 数组名作函数参数 用数组名作函数参数时,,#include ,void main,(),float average,(,float array,10,),;,/*,函数声明 *,/,float score10 , aver,;,int,;,printf,(,input,scores,:,);,for,(;,),scanf,(,,,score,);,printf,(,);,aver,average,(,score,);,printf,(, average score is,.,n, aver,);,#include ,float average,(,float array,10,),int,;,float aver,,;,for (,;,),;,;,return,(,aver,);,运行情况如下:,input,scores,:, ,.5, ,.5, ,average score is 83.40,float average (float array10,例,8.,形参数组不定义长度,#include ,void main,(),float average,(,float array ,,,int,),;,float score_15,8.5,97,91.5,60,55;,float score_2,10,= 67.5,89.5,99,6,.5,77,89.5,76.5,54,60,99.5;,printf(“the average of class A is %6.2f,n”,,,average(score_1,5);,printf(“the average of class B is %6.2f,n”,,,average(score_2,10);,例 8.形参数组不定义长度,float average,(,float array ,,,int,),int,;,float aver,,,su,array0,;,for,(,1,;),sum,sum,array,;,aver,sum,;,return,(,aver,);,运行结果如下:,the average of class A is 80.40,The average of class,is 78.20,float average(float array ,例,8.13,用选择法对数组中,10,个整数按由小到大排序。,将前一章书写的选择法排序的程序改写为函数,数组名作函数参数。,编写函数:将字符串逆置。,思考:函数需要返回值吗?,编写程序:判断一个字符串是否是回文串,如果是回文串返回整数值,1,,否则返回,0,例 8.13 用选择法对数组中10个整数按由小到大排序。,8.7.3.,多维数组名作函数参数,程序:,#include ,void main,(),max_value ( int array,4);,int a34=1,3,5,7,2,4,6,8,15,17,34,12,;,printf,(,max value is,,,max_value(a),);,用多维数组名作为函数实参和形参。在被调函数中对形参数组定义时可以指定每一维的大小 。,8.7.3. 多维数组名作函数参数程序: 用多维数组,max_value,(,int array, ,4,),int,,,max,;,max=array,;,for,(,=,;),for,(;,),if,(,array,),max= array,;,return,(,max,);,运行结果如下:,Max value is 34,max_value ( int array 4)运,8.8,局部变量和全局变量,8.8.1,局部变量,内部变量:,在一个函数内部定义的变量称内部变量。,它只在本函数范围内有效,即:只有在本函数内才能使用这些变量,故称为“局部变量” 。,8.8局部变量和全局变量 8.8.1局部变量内部变量:在一,例:,float f1( int a),/*,函数,f1 */,int b,c;,/* a,、,b,、,c,有效*,/,char f2(int x,int y),/*,函数,f2 */,int i,j;,/* x,、,y,、,i,、,j,有效*,/,void main( ),/*,主函数*,/,int m,n;,/* m,、,n,有效*,/,例:,主函数中定义的变量只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。,主函数也不能使用其他函数中定义的变量,。,#include,void main(),int a=3,b=2,c;,c=+b;,fun(),int c=12;,printf(%d ,c);,主函数中定义的变量只在主函数中有效,而不因为在主函数中定义而,(2),不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。,#include,void main(),int a=3,b=2,c;,c=+b;,fun(),int c=12;,printf(%d ,c);,(2) 不同函数中可以使用相同名字的变量,它们代表不同的对象,(3),形式参数也是局部变量。,(4),在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为,“,分程序,”,或,“,程序块,”,。,#include,void main(),int a=3,b=2,c=1;,c-=+b;,int c;,c=b*2;,printf(%d ,c);,printf(%d,%d,%d,a,b,c);,(3) 形式参数也是局部变量。,8.8.2,全局变量,外部变量:,函数之外定义的变量称为外部变量。外部变量可以为本件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。所以也称全程变量。,不必要时不要使用全局变量,,#include,int c=1;,void main(),int a=3,b=2; c-=+b;,printf(%d,%d,%d,a,b,c);,fun(),int b=2;,printf(%d ,b-c);,8.8.2 全局变量外部变量:函数之外定义的变量称为外部变,例,8.,6,外部变量与局部变量同名,#include ,int a=3,b=5;,/* a,b,为外部变量*,/ a,b,作用范围,void main ( ), int a=8;,/*a,为局部变量 *,/,局部变量,a,作用范围,printf (%d, max (a,b);,全局变量,b,的作用范围,max (int a, int b),/*a,b,为局部变量 *,/, int c;,c=ab?a:b;,形参,a,、,b,作用范围,return (c);,运行结果为,8,例 8.6 外部变量与局部变量同名运行结果为 8,8.9,变量的存储类别,8.9.1,动态存储方式与静态存储方式,从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。,从变量值,存在的时间角度来分,,又可以分为静态存储方式和动态存储方式。,静态存储方式:,指在程序运行期间由系统分配固定的存储空间的方式。,动态存储方式:,则是在程序运行期间根据需要进行动态的分配存储空间的方式。这个存储空间可以分为三部分:,1.,程序区,2.,静态存储区,3.,动态存储区,8.9 变量的存储类别 8.9.1 动态存储方式与静态存,变量和函数有两个属性:,数据类型,和,数据的存储类别,。,存储类别指的是数据在内存中存储的方式。,存储方式分为两大类:静态存储类和动态存储类。包含:,自动的(,auto,);,静态的(,static,);,寄存器的(,register,);,外部的(,extern,),。,根据变量的存储类别,可以知道变量的作用域和生存期。,变量和函数有两个属性:数据类型和数据的存储类别。存储,8.9.2 auto,变量,自动变量,auto,:,不专门声明为,static,存储类别的局部变量都是动态分配存储空间,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。,函数中的形参和在函数中定义的变量,(,包括在复合语句中定义的变量,),,都属此类。,自动变量用关键字,auto,作存储类别的声明。,例如:,int,(,int,),*定义,f,函数,为形参 *,auto int,,;,/*,定义、为自动变量 *,8.9.2 auto变量自动变量auto:不专门声明为sta,8.9.3,用,static,声明局部变量,当函数中的局部变量的值在函数调用结束后不消失而保留原值时,该变量称为静态局部变量。用关键字,static,进行声明。,8.9.3 用static声明局部变量 当函数中,例,8,7,考察静态局部变量的值,#include ,void main(),int f(int);,int a=2,i;,for(i=0;i3;i+),printf(%d,f(a);,int f(int a),auto int b=0;,static c=3;,b=b+1;,c=c+1;,return(a+b+c);,例87 考察静态局部变量的值,对静态局部变量的说明:,(,1,) 静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储区空间而不占静态存储区空间,函数调用结束后即释放。,(,2,)对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。,对静态局部变量的说明:,(,3,)如在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值(对数值型变量)或空字符(对字符变量)。,而对自动变量来说,如果不赋初值则它的值是一个不确定的值。,(,4,)虽然静态局部变量在函数调用结束后仍然存在,但其他函数不能引用它。,(3)如在定义局部变量时不赋初值的话,则对静态局部变量来说,,例,8,8,输出到的阶乘值,#include ,void main(),int fac(int n);,int i;,for(i=1;iy?x:y;,return(z); ,1. 在一个文件内声明外部变量例820 用extern声明,2.,在多文件的程序中声明外部变量,#include,int A; /*,定义外部变量*,/,void main(),int power(int); /*,函数声明*,/,int b=33,c,d,m;,printf(enter the number a and its power m:n);,scanf(%d,%d,c=A*b;,printf(%d*%d=%dn,A,b,c);,d=power(m);,printf(%d*%d=%dn,A,m,d);,例,8.21,用,extern,将外部变量的作用域扩展到其他文件。本程序的作用是给定的值,输入和,求,和,a,m,的值。文件,file,.,中的内容为:,2. 在多文件的程序中声明外部变量#includestdi,文件,file,中的内容为:,extern A; /*,声明,A,为一个已定义的外部变量*,/,int power(int n),int i,y=1;,for(i=1;i=n;i+),y*=A;,return(y);,程序的运行方式看C语言程序设计题解与上机指导(第三版)221页16.4的小节的内容。,文件file中的内容为: 程序的运行方式,8.9.6,用,static,声明外部变量,在程序设计中,某些外部变量只限于被本文件引用,而不能被其他文件引用。这时可以在定义外部变量时加一个,staitic,声明。,例如:,file1.c file2.c,static int A; extern int A;,void main ( ) void fun (int n), , A=A*n;,8.9.6 用static声明外部变量在程序设计中,某些,8.9.7,关于变量的声明和定义,定义性声明,:,需要建立存储空间的,(,如:,int a; ),声明。,引用性声明,:,不需建立存储空间的声明(,extern a,;,),。,注意:,声明包括定义,但并非所有的声明都是定义。对“,int a;”,而言,它既是声明,又是定义。而对“,extern a;”,而言,它是声明而不是定义。,8.9.7 关于变量的声明和定义定义性声明:需要建立存储空,8.9.8,存储类别小结,从作用域角度分,有局部变量和全局变量。它们采用的存储类别如下:,局部变量包括:,自动变量、 静态局部变量、寄存器变量。,形式参数可以定义为自动变量或寄存器变量。,全局变量包括:,静态外部变量、外部变量。,8.9.8 存储类别小结从作用域角度分,有局部变量和全局变,(,2,)从变量存在的时间来区分,有动态存储和静态存储两种类型。静态存储是程序整个运行时间都存在,而动态存储则是在调用函数时临时分配单元。,动态存储 :自动变量、寄存器变量、形式参数。,静态存储:静态局部变量、静态外部变量 、外部变量。,(2)从变量存在的时间来区分,有动态存储和静态存储两种类型。,(3),从变量值存放的位置来区分,可分为:,内存中静态存储区:静态局部变量、静态外部变量、,外部变量。,内存中动态存储区:自动变量和形式参数。,CPU,中的寄存器:寄存器变量。,(3) 从变量值存放的位置来区分,可分为:,(4),static,对局部变量和全局变量的作用不同。对局部变量来说,它使变量由动态存储方式改变为静态存储方式。而对全局变量来说,它使变量局部化,但仍为静态存储方式。从作用域角度看,凡有,static,声明的,其作用域都是局限的,或者是局限于本函数内,或者局限于本文件内。,(4) static对局部变量和全局变量的作用不同。对局部变,8.10,内部函数和外部函数,根据函数能否被其他源文件调用,将函数区分为,内部函数,和,外部函数,。,8.10.1,内部函数,如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加,static,。即,static,类型标识符 函数名,(,形参表,),例如,:,static int fun ( int a , int b ),8.10 内部函数和外部函数 根据函数能否被其他源文件调用,8.10.2,外部函数,(1),定义函数时,如果在函数首部的最左端加关键字,extern,则表示此函数是外部函数,可供其他文件调用,。例如,函数首部可以写为,extern int fun (int a, int b),,这样,函数,fun,就可以为其他文件调用。如果在定义函数时省略,extern,则隐含为外部函数。,(2),在需要调用此函数的文件中,用,extern,对函数作声明,表示该函数是在其他文件中定义的外部函数 。,8.10.2 外部函数(1) 定义函数时,如果在函数首部的,例,8.22,有一个若干字符的字符串,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现。,File1.c,(文件),#include ,void main(), extern void enter_string(char str);,extern void detele_string(char str,char ch);,extern void print_string(char str);/*,以上,3,行声明在本函数中将要调用的在其他文件中定义的,3,个函数*,/,char c;,char str80; enter_string(str);,scanf(%c,detele_string(str,c);,print_string(str); ,例 8.22 有一个若干字符的字符串,今输入一个字符,要求程,file,(文件),#include ,void enter_string(char str80) /*,定义外部函数,enter-string*/, gets(str); /*,向字符数组输入字符串*,/,file,(文件),void delete_string(char str,char ch),*定义外部函数,delete_string *, int i,j;,for(i=j=0;stri!=0;i+),if(stri!=ch),strj+=stri;,strj=0;,file(文件),file,(文件),#include ,void print_string(char str),printf(%sn,str);,运行情况如下:,(,输入), (输入要删去的字符), (输出已删去指定字符的字符串),程序的运行方式看C语言程序设计题解与上机指导(第三版)221页16.4的小节的内容。,file(文件)运行情况如下: 程序的,
展开阅读全文