版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第 6 章 函 数 和 模 块 设 计 7/29/20221精选课件第 6 章 函数和模块设计 6.1 结构化程序设计 6.2 函数的定义和调用 6.3 程序嵌套调用和递归调用 6.4 作用域和存储类型 6.5 内部函数和外部函数 6.6 模块化程序设计 6.7 应用举例 7/29/20222精选课件 对大千世界的许多描述大都可以在计算机中运用程序设计中的函数问题来解决,C语言程序设计也不例外。 一个功能较大的系统,它一定包含有若干个相对独立的子功能,通过子程序模块来描述这些子功能,再通过对这些子程序的组织和调用,来实现整个程序的功能要求。而这些功能比较独立的子程序模块则称之为函数 。本章用于
2、揭开函数的真面目!7/29/20223精选课件6.1 结构化程序设计 6.1.1 结构化程序设计的基本概念结构化程序设计基本思想: 将一个大的程序按功能分割成一些子模块,再通过对这些子模块的组织和调用,来实现整个程序的功能要求。7/29/20224精选课件#include stdio.h void main( ) float a,b,c,v; scanf(”%f,%f,%f”,&a,&b,&c); v=volume(a,b,c); print_message( ); float volume(float a,float b,float c) float v; v=a*b*c; return(v
3、); void print_message( ) printf(”v=%f”,v); 输出体积组织和调用计算立方体示例:编程序计算一立方体的体积,并在屏幕上输出。7/29/20225精选课件6.1 结构化程序设计 6.1.1 结构化程序设计的基本概念 结构化程序设计特点:各模块相对独立、功能单一、结构清晰;控制了程序设计的复杂性;提高元件的可靠性缩短开发周期;避免程序开发的重复劳动;易于维护和功能扩充;开发方法: 自上向下,逐步求精 ,模块化 ,限制使用goto语句。 7/29/20226精选课件6.1 结构化程序设计 6.1.2 结构化程序设计的基本特征 1. 程序的三种基本结构 AB顺序结
4、构图 条件AB真假选择结构图 条件A假真循环结构图 7/29/20227精选课件2. C语言是模块化程序设计语言C程序结构ABCDEFGHI7/29/20228精选课件3.程序设计采用自顶向下逐步细化过程 工资计算程序工资计算信息输入工资额计算工资表打印应发部分扣除部分基本工资其他补贴水电、公积金7/29/20229精选课件6.2 函数的定义和调用 函数是C语言程序的一种基本组成部分, C语言程序的功能是通过函数之间的调用来实 现,一个完整的C语言程序可由一个或多个函 数组成。 0;-x) y=y*x; return(y); 传统式例 有参函数 long facto(int x) long y
5、; for(y=1;x0;-x) y=y*x; return(y); 现代式函数类型 函数名(形参类型说明表)说明部分语句部分现代格式函数返回值类型缺省 int 型无返回值 void合法标识符可以为空也可以有多个参数函数体例 无参函数 void print_message( ) printf(”v=%f”,v); 例 空函数myfile( ) 函数体为空7/29/202213精选课件6.2 函数的定义和调用 6.2.2 函 数 的 调 用 一.函数调用格式及执行过程 调用形式函数名(实参列表);说明:实参与形参个数相等,类型一致,按顺序一一对应;实参列表求值顺序,因系统而定(Turbo C 自
6、右向左);实参的量可以是常量、有值的变量或运算表达式. 7/29/202214精选课件#include stdio.h void main( ) int i=1,n; n=f(i,+i); printf(”nn=%dn”,n); f(int a,int b) int c; if(a=b) c=1; else c=0; return(c); 自右向左顺序 #include stdio.h void main( ) int i=1,n; n=f(i,+i); printf(”nn=%dn”,n); f(int a,int b) int c; if(a=b) c=1; else c=0; retur
7、n(c); 自左向右顺序 【例6_3】 实参求值顺序举例。 运行结果:n=0 运行结果:n=1 i(1),+i(2)a(1),b(2)c=0;i(2),+i(2)a(2),b(2)c=1;7/29/202215精选课件函数调用语句的执行过程: 首先计算每个实参表达式的值,并把此值存入所对应 的形参单元中, 执行流程转入函数体,执行函数体中的各语句。 函数体执行完之后,return (c)返回到调用该函数的 函数中的调用处的下一条语/*计算面积*/ #include stdio.h void main( ) int x=5,y=4,s=0; s=f(x,y); printf(”ns=%dn”,s
8、); f(int a,int b) c=a*b; return(c); x=5y=4a=5b=4c=5*4=20s=20运行结果:s=20 7/29/202216精选课件二. 函 数 的 调 用 方 式 3. 以函数调用中的一个实际参数形式调用 例如 k=hust(hust(m,n),j); printf(”%d”,power(a,b); 2. 以函数表达式的一个运算对象形式调用 例如 k=hust(m,n)*hust(i,j); 1. 以函数调用语句形式调用例如 hust( ); 7/29/202217精选课件三.对被调用函数的使用说明 在程序中调用另一个函数时,要满足以下三个条件: 被调用
9、函数可以是已存在的用户自定义函数或库函数。 #include stdio.h void main( ) int x=5,y=4,s=0; s=f(x,y); printf(”ns=%dn”,s); f(int a,int b) c=a*b; return(c); 用户自定义函数库函数 若是库函数,应用#include命令将有关库函数所需的信息包含到本文件中 #include stdio.h void main( ) printf( “*”); 若是用户自定义的函数,且该函数与调用它的函数(即调用函数)在同一个源文件中,则在调用函数中应对被调用函数返回值的类型加以说明。 7/29/202218精
10、选课件#include stdio.h void main( ) float volume(float a,float b,float c) float x,y,z,v; scanf(”%f%f%f”,&x,&y,&z); v=volume(x,y,z); printf(”v=%fn”,v); float volume(float a,float b,float c) float d; d=a*b*c; return(d); 【例6_4】 求长方形体积的程序。 对自定义函数volume说明 调用自定义函数volume 7/29/202219精选课件6.2 函数的定义和调用 6.2.3 函数的返
11、回值 返回语句形式return(表达式);说明:系统默认的返回值类型为int型 当函数有返回值时,凡是允许表达式出现的地方,都可以调用该函数 当函数没有返回值时,函数的返回值类型可以说明为void型(空类型)若无return语句,遇 时,自动返回调用函数函数中可有多个return语句或return 表达式;或return ;功能:利用return语句,将计算结果(或不带结果)返回给调用程序,同时,也使程序的执行流程转到调用语句的下一语句去执行。7/29/202220精选课件 float count(int n) int i; float s; if(n=0); printf(”The%d is
12、 invalid”,n); return(0); else s=0; for(i=1;i=n;i+) s+=1/(float)i; return(s); 【例6_5】编一函数,求112131n的值。 强制转换成实型 7/29/202221精选课件 void spc(int n) int i; for(i=0;in;i+) printf(”%c”, ); return(0); 【例6_6】 打印n个空格的函数。 void spc(int n) int i; for(i=0;in;i+) printf(”%c”, ); 返回调用函数 或7/29/202222精选课件void line(int n)
13、 line(int n) int i; for(i=1;i=n;i+) printf(”%c”,-); return; 调用该函数: printf(”%d”,line(30); 当无返回值的函数将void省掉时, 函数将返回一个不确定的值。例如: 输出一段虚线的同时,还输出line函数的返回值,它是一个不确定的值。引起编译错误 7/29/202223精选课件 double power(float x,int n) int i; double pw; pw=l; for(i=1;i=n;i+) pw*=x; return pw; 【例6_7】编一函数,求x的n次方的值,其中n是整数。 将 x、n
14、 做为函数参数 结果通过return语句返回调用程序 7/29/202224精选课件 to_str(int n) char str10; int i; if(n0); while(-i=0) putchar(stri); 【例6_8】将一个给定的整数转换成相应的字符串后显示出来。 将数值型的数据转换成数值字符的内码 7/29/202225精选课件正确的形参定义 int hust(a,b) int a,b; int hust(int a,int b)或错误的形参定义 int hust(int a,b) int b; int hust(int a,b)或6.2 函数的定义和调用 6.2.4 函数参
15、数及函数间的数据传递 形式参数:定义函数时函数名后面括号中的变量名。实际参数:调用函数时函数名后面括号中的表达式。例如形参与实参实参的定义 s=hust(x,y); 7/29/202226精选课件/*计算面积*/ #include stdio.h void main( ) int x=5,y=4,s=0; s=f(x,y); printf(”ns=%dn”,s); f(int a,int b) c=a*b; return(c); 实参 形参 s=f(x,y);(main 函数)(f 函数)f(int a,int b)c=a*b; return(c); 7/29/202227精选课件6.2 函数
16、的定义和调用 6.2.4 函数参数及函数间的数据传递 形式参数:定义函数时函数名后面括号中的变量名。实际参数:调用函数时函数名后面括号中的表达式。形参与实参说明:实参可以是常量、已赋值的变量或表达式。实参在次序、类型和个数上应与相应形参表中的形参保持一致。 通常,当需要从调用函数中传值(或传地址)到被调用函数中的形参时应设置实参。7/29/202228精选课件6.2 函数的定义和调用 6.2.4 函数参数及函数间的数据传递 值的传递 :调用函数将实参(常数、变量、数组元素或可计算的表达式)的值传递到被调用函数形参设置的临时变量存储单元中,被调用函数形参值的改变对调用函数的实参没有影响。调用结束
17、后,形参存储单元被释放,实参仍保持原值不变。 传递形参值的两种方法 特点 :形参与实参占用不同的内存单元.单向传递7/29/202229精选课件#include stdio.h void main( ) int i=25; printf(”The value of i in main( ) before calling sqr(x) is %dn”,i); printf(”Calling sqr(x):sqr(%d)=%dn”,i, sqr(i) ); printf(”The value of i in main( ) after calling sqr(x) is %dn”,i); sqr(
18、int x) x=x*x; return(x); 【例6_9】值的传递程序举例 实参值复制给形参25i:调用前:调用:25x:25i: 运行结果: The value of i in main( ) before calling sqr(x) is 25 Calling sqr(x):sqr(25)=625 The value of i in main( ) after calling sqr(x) is 25sqr:25i:6252525x:25i:调用结束: 结论: 在值的传递调用中,只是实参的复制值被传递, 被调用函数中的操作不会影响实参的值。7/29/202230精选课件6.2 函数的
19、定义和调用 6.2.4 函数参数及函数间的数据传递 地址的传递 :调用函数将实参(数组名或指针型变量)的地址作为参数传递给形参。若实参是数组名,则调用函数将实参数组的起始地址传递给形参的临时变量单元;若实参是指针变量或地址表达式,则调用函数将实参指针变量所指向单元的地址或实参的地址传递给形参的临时变量存储单元。 传递形参值的两种方法 特点 :形参与实参占用相同的内存单元.双向传递实参和形参必须是地址常量或变量7/29/202231精选课件void f(int b ) int max,max_i,i; max=b0,max_i=0; for(i=0;i10;i+) if(maxbi) max=b
20、i;max_i=i; max=b0; b0=bmax_i; bmax_i=max; return; #include stdio.h void main( ) void f(int b ); int a10,i; for(i=0;i10;i+) scanf(”%d”,&ai); f(a); for(i=0;i10;i+) printf(”n%4d”,ai); 【例6_11】将数组中的最大元素值与第一个元素值交换 运行结果: 0 1 2 3 4 5 6 7 8 9 9 1 2 3 4 5 6 7 8 0 调用前0a9b调用0a9交换b9a0返回9a0 结论: 在地址的传递调用中,数组b与数组a共
21、用同一存储空间。 所以被传递的数据在被调用函数中对存储空间的值做出某种 变动后,必然会影响到使用该空间的调用函数中变量的值。 实参数组的起始地址传递给形参7/29/202232精选课件6.2 函数的定义和调用 6.2.4 函数参数及函数间的数据传递 一、非数组名作为函数参数 参数传递的两种形式 当非数组名作为函数参数,在函数调用时,C语言编译系统根据形参的类型为每个形参分配存储单元,并将实参的值复制到对应的形参单元之中,形参和实参分别占用不同的存储单元,且形参值的改变不影响与其对应的实参,即按“值的传递”方法操作。 7/29/202233精选课件 f(int a,int b) a=a+2; b
22、=b+4; printf(”a=%d,b=%dn”,a,b); return(a); #include stdio.h void main( ) int f(int a,int b); int x=1,y=2,z; static int a =0,1,2,3,4; z= f(x,y) ; printf(”z=%d,x=%d,y=%dn”,z,x,y); z= f(a3,a4); printf(”z=%d,a3=%d,a4=%dn” ,z,a3,a4); z= f(x,y+1); printf(”z=%d,x=%d,y=%dn”,z,x,y); 【例6_12】非数组名作为参数的值的传递程序举例
23、运行结果: a=3,b=6 z=3,x=1,y=2a=5,b=8 z=5,a3=3,a4=4a=3,b=7 z=3,x=1,y=27/29/202234精选课件6.2 函数的定义和调用 6.2.4 函数参数及函数间的数据传递 二、数组名作为函数参数 参数传递的两种形式 单个数组元素可以作为函数参数,这同非数组名作为函数参数的情形完全一样,即遵守”值传递”方式。 7/29/202235精选课件1、数组名作为函数参数的表示方法 当数组名作为函数参数时,需要对其类型进行相应的说明 例如 int test(int array10) . 若数组说明时不指定数组的长度 ,可用另一个参数来表示数组的长度 例
24、如 int test(int array,int n ) . 用形参n来表示array数组的实际长度,更灵活7/29/202236精选课件int solve( int a ,int n) int sum,i; sum=0; for(i=0;in;i+) if(ai!=0) sum+; return(sum); 【例6_13】编一函数,用来统计一个一维数组中非0元素的个数用形参n来表示a数组的实际长度。7/29/202237精选课件1、数组名作为函数参数的表示方法 当多维数组名作为函数参数时,除第一维可以不指定长度外,其余各维都必须指定长度。例如 check(float a 10,float n
25、) . 下面的参数说明都是不正确的: 例如 float a ; 或 float a10 ; . 7/29/202238精选课件说明: 用数组名作为函数参数时,应该在调用函数和被调用函数 中分别定义数组。 实参数组和形参数组类型应一致,否则出错。 形参数组的大小应大于等于实参数组的大小,否则得不到 实参数组的全部值。 特别注意的是,数组名作为函数参数时,是将实参数组 的首地址传给形参数组,两数组的对应元素占用同一内 存单元。传递时按数组在内存中排列的顺序进行。7/29/202239精选课件2、数组名作为函数参数的传递方式 数组名作为函数参数时,不是采用“值传递”方式, 而是采用“地址传递”方式。
26、 这意味着形参数组中某一元素的改变,将直接影响到 与其对应的实参数组中的元素。 7/29/202240精选课件void sort(int array10) int i,j,k,t; for(i=0;i9;i+) k=i; for(j=i+1;j10;j+) if(arrayjarrayk) k=j; t=arrayk;arrayk=arrayi; arrayi=t; #include stdio.h void main( ) int x10,i; void sort(int array10); for(i=0;i10;i+) scanf(”%d,”,&xi); sort(x); printf(
27、”The sorted array:n”); for(i=0;i10;i+) printf(”%d,”,xi); printf(”n”); 【例6_14】将一个10个元素的一维数组用函数调用实现选择排序。 9,8,7,6,5,4,3,2,1,0 The sorted array: 0,1,2,3,4,5,6,7,8,9调用前9x009 调用9x009array 交换0 x909array 返回0 x909scanf(”%d,”,&xi);寻找排序7/29/202241精选课件6.3 嵌套调用和递归调用 C语言中的函数定义是互相独立的,函数和函数之间没有从属关系,即一个函数内不允许包含另一个函数
28、的定义。一个函数既可以被其他函数调用,同时,它也可以调用别的函数,这就是函数的嵌套调用。函数的嵌套调用为自顶向下、逐步求精及模块化的结构化程序设计技术提供了最基本的支持。=0) break; result=fact(n) ; printf(”Result=%ld”,result);【例6_16】 从键盘输入一非负整数n,并求出n!的值。n!=n*(n-1)!结果分析:n=4 f(4)= 4*fac(4-1) =3 f(3)= 3*fac(3-1) =2 f(2)= 2*fac(2-1) =1 f(1)= 1*fact(1-1) =0 f(0)= 1回推递推运行情况:Input a number
29、: 4Result =24递归调用嵌套调用if(n=0) /*递归终止条件*/ f=1;递归过程的两个阶段:fact(4)是主函数调用的。在一次调用fact函数时并不是立即得到fact(4)的值,而是一次又一次地进行递归调用(回推),直到fact(1)时才有确定的值。之后,再递推出fact(2)、 fact(3)、 fact(4)的值。7/29/202246精选课件double xpower(float x,int n) if(n=0) return(1); else return(x*xpower(x,n-1);#include stdio.h void main( ) double xpo
30、wer(float x,int n); float x; int n; double r scanf(”%f%d”,&x,&n); r=xpower(x,n); printf(”Result=%f”,r);【例6_17】编一程序,利用函数的递归调用求x的n次方的值,其中n为正整数。 运行情况:2,3Result =8 小结:任何有意义的递归调用总是由两部分组成:即递归方式与递归终止条件。 if(n=0) /*递归终止条件*/ return(1);7/29/202247精选课件6.4 作用域和存储类型 变量是对程序中数据的存储空间的抽象 变量的属性数据类型:变量所持有的数据的性质(操作属性)存储
31、属性存储器类型:寄存器、静态存储区、动态存储区生存期:变量在某一时刻存在 静态变量与动态变量作用域:变量在某区域内有效 局部变量与全局变量 变量的存储类型 auto 自动型 register 寄存器型 static 静态型 extern 外部型 变量定义格式: 存储类型定义符 数据类型 变量名表;如: int sub; auto int x,y,z; register int n; static float a,b;7/29/202248精选课件6.4 作用域和存储类型 6.4.1 局部变量及其存储类型 定义在 函数 或 复合语句 内部定义的变量称为 局部变量。 说明主函数main中定义的变量
32、也只在主函数中有效,其它函数不能引用;不同函数中可以使用相同名字的变量,它们代表不同的对象,占用不同的内存单元,互相独立;形式参数也是局部变量;可以在复合语句中定义变量,其作用域只是本复合语句。7/29/202249精选课件 float hust1(int a) int x, y; 举 例局部变量a、x、y的作用范围 float hust2(int b,int c) char s; 局部变量b、c、s的作用范围void main( ) int m, n; 局部变量m、n的作用范围7/29/202250精选课件举 例#include ”stdio.h” void main( ) int p, q
33、; int x; x=p+q; x 的有效范围p、q的有效范围7/29/202251精选课件6.4 作用域和存储类型 6.4.1 局部变量及其存储类型 1.自动存储变量 auto自动存储变量 在函数或复合语句中定义和说明的变量,通常称为自动变量。自动变量前可以冠以“auto”,若变量前不加任何存储类别说明 ,则按缺省规则都为自动存储类别的变量。作用域: 自动变量通常是局部变量,它的作用域仅限于定义它的那个函数或复合语句。它的可见性与生存期和作用域相同。 auto float a; float a;或7/29/202252精选课件【例6_18】 不同函数中的同名变量#include stdio.
34、hvoid main( ) int a; a=0; data( ); a=a+100; printf(”main:a=%dn”,a);data( ) int a; a=-199; printf(”data:a=%dn”,a);运行结果:data:a=-199main:a=100不指定为auto型不指定为auto型#include stdio.hvoid main( ) int a; a=1; data( ); a=a+100; printf(”main:a=%dn”,a);data( ) int a; printf(“da=%dn,a); a=-199; printf(”data:a=%dn”
35、,a);运行结果: da=1 data:a=199 main:a=1017/29/202253精选课件【例6_18】 不同函数中的同名变量#include stdio.hvoid main( ) int a; a=10; printf(“ma=%d,%xn,a,&a); data( ); a=a+100; printf(”main:a=%dn”,a ,&a);data( ) int a; printf(“da=%dn,a ,&a); a+=1; printf(“daa=%d,%xn,a,&a); a=-199; printf(”data:a=%dn”,a ,&a);运行结果:ma=10,ffd
36、cda=404,ffd6daa=405,ffd6data:a =199,ffd6main:a=110,ffdc7/29/202254精选课件6.4 作用域和存储类型 6.4.1 局部变量及其存储类型 2. 静态局部变量 static 如果希望在函数调用结束后仍然保留函数中定义的局部变量的值,则可以将该局部变量定义为静态局部变量。 静态局部变量前可以冠以“static ” 例如 static int t,s; 说明:静态局部变量的作用域在定义它的函数内部,它的值在函 数调用结束后并不消失,但其他函数仍然不能访问它。静态局部变量赋初值是在编译过程中进行的,且只赋一次 初值。而且连续保留上一次函数调
37、用时的结果。静态局部变量的默认初值数值型为0,字符型为Null7/29/202255精选课件【例6_19】编一程序,观察静态局部变量在调用过程中的情况。 #include stdio.h void test( ) static int a=0; printf(”a=%dn”,a); +a; void main( ) int i; for(i=0;i4;i+) test( ); 运行结果: a=0 a=1a=2a=37/29/202256精选课件#include int func(int a,int b) static int m=0, i=0; i+=m+1; m=i+a+b; return(
38、m); main() int k=3,m=2,p; p=func(k,m); printf(“p1=%dn”,p); p=func(k,m); printf(“p2=%dn”,p); 运行结果:p1= 课堂练习:看程序写结果*i=i+(m+1)=0+(0+1)=1*m=1+3+2=6*i=i+(m+1)=1+(6+1)=8*m=8+3+2=13*6p2=137/29/202257精选课件6.4 作用域和存储类型 6.4.1 局部变量及其存储类型 3. 寄存器变量 register 为提高程序的运行速度,可将使用十分频繁的局部变量说明为寄存器变量,即在局部变量前冠以register,告知编译系统
39、将其存储在CPU的寄存器中 void test_r(register int n) register char c; . 说明:变量的存储类型为寄存器变量时,auto说明符可省,冠以register说明符即可寄存器变量的使用与机器的硬件特性有关,有一些限制:如寄存器变量的个数;它只适用于自动变量和函数的形参;它的类型只能是char、short int、unsigned int、int和指针型;不允许对寄存器变量取地址等。 Turbo C中寄存器变量只能用于整型和字符型,且限制最多只允许定义两个 寄存器变量。一旦超过,系统就自动地将其余的作为非寄存器变量来处理。 7/29/202258精选课件i
40、的作用范围【例6_20】 输出1到5的阶乘的值。 #include stdio.h void main( ) int fac(int n); int i; for(i=1;i=5;i+) printf(”%d!=%dn”,i,fac(i); int fac(int n) register int i,f=1; for(i=1;i=n;i+) f=f*i; return(f); 运行结果: 1!=1 2!=23!=64!=24i、f的作用范围5!=1207/29/202259精选课件【例6_21】编一程序,输入10名学生的成绩,并求出平均成绩 #include stdio.h float asc
41、ore(float a ,int n) register int i; float sum; sum=0; for(i=0;in;i+) sum+=ai; return(sum/n); void main( ) float array10; register int i; for(i=0;i10;i+) scanf(”%f”,&arrayi); printf(”Average score=%f”,; ascore(array,10);i的作用范围i的作用范围7/29/202260精选课件6.4 作用域和存储类型 6.4.2 全局变量及其存储类型 定义一个源程序文件可以包含一个或若干个函数。在函
42、数之外定义的变量称为全局变量或全程变量(又称外部变量)。 全局变量与局部变量的区别:全局变量在函数之外定义,局部变量在函数之内定义;局部变量在本函数之内有效,全局变量从定义变量的位置开始到本源文件结束均有效。编译时全局变量分配在静态存储区,而局部变量则不一定。7/29/202261精选课件【例6_22】编一程序,打印九九表 #include stdio.h void row(); int a=1; /*外部变量*/ void main( ) int k; for(k=1;k=9;+k,+a) row( ); void row( ) int b; for(b=1;b=a;+b) printf(”
43、%4d”,a*b); printf(”n”); k的有效范围b的有效范围作用域a7/29/202262精选课件6.4 作用域和存储类型 6.4.2 全局变量及其存储类型 1. 外部变量 extern 外部变量 没有说明为static的全局变量,其存储类型都是外部的,统称为外部变量。外部变量说明extern 数据类型 变量表;注意:凡在函数外定义的全局变量,按缺省规则可以不写说明extern, 但在函数体内说明其后所定义的全局变量时,要冠以extern。若一个文件要引用另一个文件中的全局变量,应该在需要引用该 变量的文件中,用 extern说明该变量为外部的全局变量。7/29/202263精选课
44、件【例6_23】编一程序,打印九九表 #include stdio.hvoid row();void main( ) int k; for(k=1;k=9;+k,+a) row( ); int a=1; /*定义外部变量*/ void row ( ) int b; for(b=1;b=a;+b) printf(”%4d”,a*b); printf(”n”); 作用域a作用域a扩展extern int a; /*说明外部变量*/extern只能用来说明变量,而不能用来定义变量。 7/29/202264精选课件 例如 在不同的文件中引用外部变量 文件f1.c的内容:# include “f2.c”
45、int x; /*外部变量定义*/main() int sum,y; scanf(“%d”,&y); store(); sum=x+y; printf(“sum=%d”,sum);文件f2.c的内容:extern int x; /*外部变量引用说明*/void store() x=10; 7/29/202265精选课件6.4 作用域和存储类型 6.4.2 全局变量及其存储类型 2. 静态外部变量 static 静态全局变量一定是在本文件中定义的全局变量,其存储类型说明符是static。 静态全局变量的作用域是其定义点开始到该文件的结束,在本文件外不能访问。 这种全局变量起到一个屏蔽作用。也可以
46、对函数定义成静态的,来限制函数的作用域。 静态外部变量与外部变量的相同与区别:两者都是在静态存储区中分配单元;外部变量不仅在本函数之内使用,还可以用于其他函数,但静态外部变量则不能用于其他函数;7/29/202266精选课件 例如 下面对静态全局变量的引用是错误的: file1.c static int a; /*静态外部变量定义*/main() a=1; printf(”%dn”,f(a); file2.c extern int a; /*静态外部变量引用说明*/int f(int x) x=a+x; printf(”%dn”,x); return(x);即使使用了extern说明,也无法使
47、用该变量。 7/29/202267精选课件6.5 内部函数和外部函数 C语言程序系统由若干个函数组成,这些函数既可在同一文件中,也可分散在多个不同的文件中,根据函数能否被其它源文件调用,可将它们分为内部函数和外部函数。7/29/202268精选课件6.5 内部函数和外部函数 6.5.1 内部函数(静态函数 ) 如果一个函数只能被本文件中其它函数所 调用,称为内部函数(或静态函数)。 定义时在函数类型前加static:static 类型标识符 函数名 static float hust(int a,int b) 函数hust的作用范围仅局限于定义本文件,而在其它文件中不能调用此函数。 7/29/
48、202269精选课件6.5 内部函数和外部函数 6.5.2 外 部 函 数外部函数在函数定义的前面冠以extern说明符的函数,称为外部函数。定义外部函数 extern 类型标识符 函数名说明: 在定义函数时省去了extern说明符时,则隐含为外部函数。 在需要调用外部函数的文件中,应该用extern说明所用的函数 是外部函数。7/29/202270精选课件【例6_24】输入一个字符,将已知字符串中的该字符删除,要求用外部函数实现。 /*file1.c*/#include stdio.h“void main( )extern enter_string(char str80);extern de
49、lete_string(char str ,char ch);extern print_string(char str ); char c; static char str80; enter_string(str); scanf(”%c”,&c); delete_string(str,c); print_string(str); /*file2.c*/#include “stdio.h“/*输入字符串*/ extern enter_string(char str80) gets(str);/*file3.c*/#include stdio.h“/*删除给定的字符 */extern delete
50、_string(char str ,char ch) int i,j; for(i=j=0;stri!=0;i+) if(stri!=ch) strj+=stri; strj=0; /*file4.c*/ /*打印操作结果 */extern print_string(char str ) printf(”%s”,str); 运行结果:abcdefgc cabcdefg7/29/202271精选课件上机操作过程:方法一:(1)在file1.c文件开头加入如下内容#include ”file2.c”#include ”file3.c”#include ”file4.c”(2)对file1.c文件进
51、行编译、连接、运行。方法二: 分别对4个文件进行编译得到四个目标文件 (.obj文件)。 用link功能将四个目标文件连接起来: 在MS C系统上用命令: link file1+ file2+ file3+ file4 执行结果生成一个可执行文件(.exe文件)7/29/202272精选课件6.6 模块化程序设计 在程序设计时,如果待解决的问题比较简单,所编制的程序又不大,可将整个程序放在一个模块中。但对大而复杂的设计任务,不可能由1个人用1个程序来实现。7/29/202273精选课件6.6 模块化程序设计 6.6.1 模块化程序设计方法的指导思想基本思想:将一个大的程序按功能分割成一些小模块
52、。开发方法:自顶向下,逐步求精 。特点:各模块相对独立、功能单一、结构清晰、接口简单。控制了程序设计的复杂性。提高元件的可靠性。缩短开发周期。避免程序开发的重复劳动。易于维护和功能扩充。7/29/202274精选课件C语言是模块化程序设计语言C程序结构ABCDEFGHIC是函数式语言必须有且只能有一个名为main的主函数C程序的执行总是从main函数开始,在main中结束函数不能嵌套定义,可以嵌套调用7/29/202275精选课件程序设计采用自顶向下逐步细化过程 工资计算程序工资计算信息输入工资额计算工资表打印应发部分扣除部分基本工资其他补贴水电、公积金7/29/202276精选课件6.6 模
53、块化程序设计 6.6.2 模块分解的原则 模块分解用“自顶向下”的方法进行系统设计,即先整体后局部。复杂系统化大为小,化繁为简。按功能划分法把模块组成树状结构,层次清楚,提高系统设计 效率(多人并行开发),便于维护。模块的大小要适中,语句行数不大于100行。各模块间的接口要简单。尽可能使每个模块只有一个入口,一个出口。7/29/202277精选课件模块的划分和设计可参考如下规则: (1)如果一个程序段被很多模块所共用,则它应是一个独立的模块。(2)如果若干个程序段处理的数据是共用的,则这些程序段应放在一个 模块中。(3)若两个程序段的利用率差别很大,则应分属于两个模块。(4)一个模块既不能过大
54、,也不能过小。过大则模块的通用性较差,过 小则会造成时间和空间上的浪费。 (5)力求使模块具有通用性,通用性越强的模块利用性越高。(6)各模块间应在功能上,逻辑上相互独立,尽量截然分开,特别应避 免用转移语句的模块间转来转去。(7)各模块间的接口应该简单,要尽量减少公共符号的个数,尽量不用 共用数据存储单元,在结构或编排上有联系的数据应放在一个模块 中,以免相互影响,造成查错困难。 (8)每个模块的结构应尽量设计成单入口,单出口的形式。这样的程序 便于调试,阅读和理解且可靠性高。7/29/202278精选课件6.7 应 用 举 例 7/29/202279精选课件【例6_25】编一程序,从键盘为
55、一个1010维整型数组输入数据,并对该数组进行转置操作,即行、列互换。 #include stdio.hvoid rotate(int a1010)int i,j,temp; for(i=0;i10;i+) for(j=i+1;j10;j+) temp=aij; aij=aji; aji=temp; void main( )int a1010,i,j; for(i=0;i10;i+) for(j=0;j10;j+) scanf(”d”,&aij); putchar(n); rotate(a); for(i=0;i10;i+) for(j=0;j10;j+) printf(”%d”,aij);
56、说明:由于rotate函数的参数a是数组,因此,它采用的是“地址传递”方式,即rotate函数中形参a数组的改变,直接影响到在main函数中调用rotate函数时的实参数组a。7/29/202280精选课件分析:题意要求计算字符串长度。可以用字符数组来存储字符串。主函数main用来输入字符串和输出字符串长度值,函数strlen()用来计算字符串长度。其递归结束条件是元素值为0,此时,应返回字符串长度,否则应判断下一个字符。【例6_26】编写一个计算字符串长度的递归函数。 #include stdio.hint i=0;void main( )int str_len(char s); char
57、str100; printf(”Input string:n”); gets(str); printf(”Output string:n”); puts(str); i=str_len(str); printf(”The string length=%dn”,i);int str_len(char s) if(si=0) return(i); else i+; str_len(s); 说明:程序的递归函数中,若不满足条件(si=0)时,一方面长度 I 要加 1,另一方面将数组中下一个元素的地址作为实参进行递归调用。这是因为 s 是数组的第一个元素的地址,则 s+1 是第二个元素的地址, s+I
58、 是第 i+1 个元素的地址。7/29/202281精选课件【例6_27】变量存储类型及作用域应用举例 /*文件file1.c内容*/ #include stdio.h“int i=1;next( ) return(i+);void main( )int i,j; i=reset( ); for(j=1;j=3;j+) printf(”i=%dtj=%dt”,i,j); printf(”next( )=%dt”,next( ); printf(”last( )=%dt”,last( ); printf(”new(i+j)=%dt”,new(i+j); printf(”n”); /*文件file
59、2.c*/static int i=10; last( ) return(i-=1); new(int i) static int j=5; return(i=j+=+i);/*文件file3.c*/extern int i;reset() return(i); 运行结果:i=1 j=1 next( )=1 last( )=9 new(i+j)=8i=1 j=2 next( )=2 last( )=8 new(i+j)=12i=1 j=3 next( )=3 last( )=7 new(i+j)=17 7/29/202282精选课件 这是一个由三个文件组成的程序,分别是file1.c、file
60、2.c、file3.c。 在file1.c的头部对i变量进行了外部说明,照例它是全局变量,其作用域是整个文件。然而,主函数main( )内又对i变量重新作了说明,这个i是自动变量,它与外部那个全局的i无关。在函数next( )中,i在使用前已经作了外部说明,所以可直接引用,不需用extern作外部说明。在文件file2.c中,把i说明成外部静态变量,照例它的作用域是文件file2.c内。但是在new( )函数中,i为形参,和自动变量一样,它与外部静态变量i无关,而且它也与文件file1.c中的外部变量i无关。在文件file3.c中,开头就对i变量作了外部说明,因此,它与file1.c中的外部变
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年度企业咨询服务与技术转让合同2篇
- 运输合同纠纷运输合同简单版本
- 化工原理自测题:第六章(自)
- 人教版九年级化学第九单元过关训练课件
- 人教版九年级化学第八单元3金属资源的利用和保护课时1常见的金属矿石和铁的冶炼分层作业课件
- 人教版九年级化学第一单元走进化学世界3走进化学实验室课时2物质的加热仪器的连接和洗涤教学教学课件
- 最简单沙子购销合同范本
- 人教版九年级化学第二单元我们周围的空气2氧气课时2化合反应和氧化反应教学教学课件
- 客房员工年终总结
- 职业生涯规划课件
- 2024北京市租房合同自行成交版下载
- 庆祝第75个国庆节共筑中国梦大国华诞繁盛共享课件
- 2024年江西省高考化学试卷(真题+答案)
- 人教版小学语文一年级单元测试题-全册
- 2024-2030年中国PQQ行业市场发展分析及前景趋势与投资研究报告
- 2024年新青岛版四年级上册科学全册知识点六三制
- 注册消防工程师案例分析真题(完整)
- 实验室经费管理制度
- 2024-2030年中国数字商务行业市场发展趋势与前景展望战略分析报告
- 烟草专卖行政执法中存在的问题及对策研究
- 二手车交易定金合同范本5篇
评论
0/150
提交评论