函数和模块设计.ppt
第 6 章 函 数 和 模 块 设 计,第 6 章 函数和模块设计,对大千世界的许多描述大都可以在计算机中运用程序设计中的函数问题来解决,C语言程序设计也不例外。一个功能较大的系统,它一定包含有若干个相对独立的子功能,通过子程序模块来描述这些子功能,再通过对这些子程序的组织和调用,来实现整个程序的功能要求。而这些功能比较独立的子程序模块则称之为函数。本章用于揭开函数的真面目!,2023/10/6,程序设计基础(C语言)wh,4,6.1 结构化程序设计,6.1.1 结构化程序设计的基本概念结构化程序设计基本思想:将一个大的程序按功能分割成一些子模块,再通过对这些子模块的组织和调用,来实现整个程序的功能要求。,2023/10/6,程序设计基础(C语言)wh,5,#include stdio.h void main()float a,b,c,v;scanf(”%f,%f,%f”,输出体积,组织和调用,计算立方体,示例:编程序计算一立方体的体积,并在屏幕上输出。,2023/10/6,程序设计基础(C语言)wh,6,6.1 结构化程序设计,6.1.1 结构化程序设计的基本概念,结构化程序设计特点:各模块相对独立、功能单一、结构清晰;控制了程序设计的复杂性;提高元件的可靠性缩短开发周期;避免程序开发的重复劳动;易于维护和功能扩充;开发方法:自上向下,逐步求精,模块化,限制使用goto语句。,2023/10/6,程序设计基础(C语言)wh,7,6.1 结构化程序设计,6.1.2 结构化程序设计的基本特征,1.程序的三种基本结构,2023/10/6,程序设计基础(C语言)wh,8,2.C语言是模块化程序设计语言,2023/10/6,程序设计基础(C语言)wh,9,3.程序设计采用自顶向下逐步细化过程,2023/10/6,程序设计基础(C语言)wh,10,6.2 函数的定义和调用,函数是C语言程序的一种基本组成部分,C语言程序的功能是通过函数之间的调用来实 现,一个完整的C语言程序可由一个或多个函 数组成。,2023/10/6,程序设计基础(C语言)wh,11,示例:编一个程序,计算一立方体的体积,并在屏幕上输出立方体的体积。,#include stdio.h void main()float a,b,c,v;scanf(”%f,%f,%f”,说明:,C是函数式语言,必须有且只 能有一个名为main的主函数,执行总是从main函数开始,在main中结束。,一个C语言程序可由一个或 多个函数组成。,C语言中函数与函数之间都是 互相独立的,不能嵌套定义。,除main函数之外,其他函数 是通过调用来执行的。,自定义函数必须先定义后使用,volume函数中的return(v)语句是返回语句,2023/10/6,程序设计基础(C语言)wh,12,6.2 函数的定义和调用,6.2.1 函 数 的 定 义,一 般 格 式,函数类型 函数名(形参类型说明表)说明部分语句部分,传统格式,函数类型 函数名(形参表)形参类型说明说明部分语句部分,现代格式,2023/10/6,程序设计基础(C语言)wh,13,函数类型 函数名(形参类型说明表)说明部分语句部分,现代格式,函数返回值类型缺省 int 型无返回值 void,合法标识符,可以为空也可以有多个参数,例 无参函数 void print_message()printf(”v=%f”,v);,2023/10/6,程序设计基础(C语言)wh,14,6.2 函数的定义和调用,6.2.2 函 数 的 调 用,一.函数调用格式及执行过程,调用形式,函数名(实参列表);,说明:实参与形参个数相等,类型一致,按顺序一一对应;实参列表求值顺序,因系统而定(Turbo C 自右向左);实参的量可以是常量、有值的变量或运算表达式.,2023/10/6,程序设计基础(C语言)wh,15,【例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;,2023/10/6,程序设计基础(C语言)wh,16,函数调用语句的执行过程:首先计算每个实参表达式的值,并把此值存入所对应 的形参单元中,执行流程转入函数体,执行函数体中的各语句。函数体执行完之后,return(c)返回到调用该函数的 函数中的调用处的下一条语,/*计算面积*/#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);,x=5y=4,a=5b=4,c=5*4=20,s=20,运行结果:s=20,2023/10/6,程序设计基础(C语言)wh,17,二.函 数 的 调 用 方 式,3.以函数调用中的一个实际参数形式调用 例如 k=hust(hust(m,n),j);printf(”%d”,power(a,b);,2.以函数表达式的一个运算对象形式调用 例如 k=hust(m,n)*hust(i,j);,1.以函数调用语句形式调用例如 hust();,2023/10/6,程序设计基础(C语言)wh,18,三.对被调用函数的使用说明,在程序中调用另一个函数时,要满足以下三个条件:被调用函数可以是已存在的用户自定义函数或库函数。,若是库函数,应用#include命令将有关库函数所需的信息包含到本文件中,#include stdio.h void main()printf(“*”);,若是用户自定义的函数,且该函数与调用它的函数(即调用函数)在同一个源文件中,则在调用函数中应对被调用函数返回值的类型加以说明。,2023/10/6,程序设计基础(C语言)wh,19,#include stdio.h void main()float volume(float a,float b,float c)float x,y,z,v;scanf(”%f%f%f”,【例6_4】求长方形体积的程序。,对自定义函数volume说明,调用自定义函数volume,2023/10/6,程序设计基础(C语言)wh,20,6.2 函数的定义和调用,6.2.3 函数的返回值,返回语句形式,return(表达式);,说明:系统默认的返回值类型为int型 当函数有返回值时,凡是允许表达式出现的地方,都可以调用该函数 当函数没有返回值时,函数的返回值类型可以说明为void型(空类型)若无return语句,遇 时,自动返回调用函数函数中可有多个return语句,或,return 表达式;,或,return;,功能:利用return语句,将计算结果(或不带结果)返回给调用程序,同时,也使程序的执行流程转到调用语句的下一语句去执行。,2023/10/6,程序设计基础(C语言)wh,21,float count(int n)int i;float s;if(n=0);printf(”The%d is invalid”,n);return(0);else s=0;for(i=1;i=n;i+)s+=1/(float)i;return(s);,【例6_5】编一函数,求112131n的值。,强制转换成实型,2023/10/6,程序设计基础(C语言)wh,22,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”,);,返回调用函数,或,2023/10/6,程序设计基础(C语言)wh,23,void line(int n),line(int n)int i;for(i=1;i=n;i+)printf(”%c”,-);return;调用该函数:printf(”%d”,line(30);,当无返回值的函数将void省掉时,函数将返回一个不确定的值。例如:,输出一段虚线的同时,还输出line函数的返回值,它是一个不确定的值。,引起编译错误,2023/10/6,程序设计基础(C语言)wh,24,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 做为函数参数,结果通过return语句返回调用程序,2023/10/6,程序设计基础(C语言)wh,25,to_str(int n)char str10;int i;if(n0);while(-i=0)putchar(stri);,【例6_8】将一个给定的整数转换成相应的字符串后显示出来。,将数值型的数据转换成数值字符的内码,2023/10/6,程序设计基础(C语言)wh,26,6.2 函数的定义和调用,6.2.4 函数参数及函数间的数据传递,形式参数:定义函数时函数名后面括号中的变量名。实际参数:调用函数时函数名后面括号中的表达式。,例如,形参与实参,2023/10/6,程序设计基础(C语言)wh,27,/*计算面积*/#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);,实参,形参,2023/10/6,程序设计基础(C语言)wh,28,6.2 函数的定义和调用,6.2.4 函数参数及函数间的数据传递,形式参数:定义函数时函数名后面括号中的变量名。实际参数:调用函数时函数名后面括号中的表达式。,形参与实参,说明:实参可以是常量、已赋值的变量或表达式。实参在次序、类型和个数上应与相应形参表中的形参保持一致。通常,当需要从调用函数中传值(或传地址)到被调用函数中的形参时应设置实参。,2023/10/6,程序设计基础(C语言)wh,29,6.2 函数的定义和调用,6.2.4 函数参数及函数间的数据传递,值的传递:调用函数将实参(常数、变量、数组元素或可计算的表达式)的值传递到被调用函数形参设置的临时变量存储单元中,被调用函数形参值的改变对调用函数的实参没有影响。调用结束后,形参存储单元被释放,实参仍保持原值不变。,传递形参值的两种方法,特点:形参与实参占用不同的内存单元.单向传递,2023/10/6,程序设计基础(C语言)wh,30,#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(int x)x=x*x;return(x);,【例6_9】值的传递程序举例,运行结果: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 25,结论:在值的传递调用中,只是实参的复制值被传递,被调用函数中的操作不会影响实参的值。,2023/10/6,程序设计基础(C语言)wh,31,6.2 函数的定义和调用,6.2.4 函数参数及函数间的数据传递,地址的传递:调用函数将实参(数组名或指针型变量)的地址作为参数传递给形参。若实参是数组名,则调用函数将实参数组的起始地址传递给形参的临时变量单元;若实参是指针变量或地址表达式,则调用函数将实参指针变量所指向单元的地址或实参的地址传递给形参的临时变量存储单元。,传递形参值的两种方法,特点:形参与实参占用相同的内存单元.双向传递实参和形参必须是地址常量或变量,2023/10/6,程序设计基础(C语言)wh,32,void f(int b)int max,max_i,i;max=b0,max_i=0;for(i=0;i10;i+)if(maxbi)max=bi;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”,【例6_11】将数组中的最大元素值与第一个元素值交换,运行结果:0 1 2 3 4 5 6 7 8 9 9 1 2 3 4 5 6 7 8 0,结论:在地址的传递调用中,数组b与数组a共用同一存储空间。所以被传递的数据在被调用函数中对存储空间的值做出某种 变动后,必然会影响到使用该空间的调用函数中变量的值。,2023/10/6,程序设计基础(C语言)wh,33,6.2 函数的定义和调用,6.2.4 函数参数及函数间的数据传递,一、非数组名作为函数参数,参数传递的两种形式,当非数组名作为函数参数,在函数调用时,C语言编译系统根据形参的类型为每个形参分配存储单元,并将实参的值复制到对应的形参单元之中,形参和实参分别占用不同的存储单元,且形参值的改变不影响与其对应的实参,即按“值的传递”方法操作。,2023/10/6,程序设计基础(C语言)wh,34,f(int a,int b)a=a+2;b=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】非数组名作为参数的值的传递程序举例,运行结果:,a=3,b=6,z=3,x=1,y=2,a=5,b=8,z=5,a3=3,a4=4,a=3,b=7,z=3,x=1,y=2,2023/10/6,程序设计基础(C语言)wh,35,6.2 函数的定义和调用,6.2.4 函数参数及函数间的数据传递,二、数组名作为函数参数,参数传递的两种形式,单个数组元素可以作为函数参数,这同非数组名作为函数参数的情形完全一样,即遵守”值传递”方式。,2023/10/6,程序设计基础(C语言)wh,36,1、数组名作为函数参数的表示方法,当数组名作为函数参数时,需要对其类型进行相应的说明 例如 int test(int array10).,若数组说明时不指定数组的长度,可用另一个参数来表示数组的长度 例如 int test(int array,int n).,用形参n来表示array数组的实际长度,更灵活,2023/10/6,程序设计基础(C语言)wh,37,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数组的实际长度。,2023/10/6,程序设计基础(C语言)wh,38,1、数组名作为函数参数的表示方法,当多维数组名作为函数参数时,除第一维可以不指定长度外,其余各维都必须指定长度。例如 check(float a 10,float n).,下面的参数说明都是不正确的:例如 float a;或 float a10;.,2023/10/6,程序设计基础(C语言)wh,39,说明:,用数组名作为函数参数时,应该在调用函数和被调用函数 中分别定义数组。,实参数组和形参数组类型应一致,否则出错。,形参数组的大小应大于等于实参数组的大小,否则得不到 实参数组的全部值。,特别注意的是,数组名作为函数参数时,是将实参数组 的首地址传给形参数组,两数组的对应元素占用同一内 存单元。传递时按数组在内存中排列的顺序进行。,2023/10/6,程序设计基础(C语言)wh,40,2、数组名作为函数参数的传递方式,数组名作为函数参数时,不是采用“值传递”方式,而是采用“地址传递”方式。这意味着形参数组中某一元素的改变,将直接影响到 与其对应的实参数组中的元素。,2023/10/6,程序设计基础(C语言)wh,41,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,”,【例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,scanf(”%d,”,2023/10/6,程序设计基础(C语言)wh,42,6.3 嵌套调用和递归调用,C语言中的函数定义是互相独立的,函数和函数之间没有从属关系,即一个函数内不允许包含另一个函数的定义。一个函数既可以被其他函数调用,同时,它也可以调用别的函数,这就是函数的嵌套调用。函数的嵌套调用为自顶向下、逐步求精及模块化的结构化程序设计技术提供了最基本的支持。,2023/10/6,程序设计基础(C语言)wh,43,6.3 嵌套调用和递归调用,6.3.1 函数的嵌套调用,嵌套调用,一个函数既可以被其他函数调用,同时,它也可以调用别的函数,这就是函数的嵌套调用。,嵌套调用执行过程,调用函数a,调用函数b,2023/10/6,程序设计基础(C语言)wh,44,6.3 嵌套调用和递归调用,6.3.2 函数的递归调用,递归调用,在调用一个函数过程中又出现直接或间接地调用该函数本身,前者称之为直接递归调用,后者称之为间接递归调用。,2023/10/6,程序设计基础(C语言)wh,45,float func(int n)int m;float f;f=func(m);.,直接递归调用,间接递归调用,2023/10/6,程序设计基础(C语言)wh,46,long int fact(int n)long int f;if(n=0)f=1;else f=n*fact(n-1);return(f);,#include stdio.h void main()int n;long int result;long int fact(int n);while(1)printf(”Input a number:”);scanf(”%d”,【例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:4,Result=24,if(n=0)/*递归终止条件*/f=1;,递归过程的两个阶段:fact(4)是主函数调用的。在一次调用fact函数时并不是立即得到fact(4)的值,而是一次又一次地进行递归调用(回推),直到fact(1)时才有确定的值。之后,再递推出fact(2)、fact(3)、fact(4)的值。,2023/10/6,程序设计基础(C语言)wh,47,double xpower(float x,int n)if(n=0)return(1);else return(x*xpower(x,n-1);,#include stdio.h void main()double xpower(float x,int n);float x;int n;double r scanf(”%f%d”,【例6_17】编一程序,利用函数的递归调用求x的n次方的值,其中n为正整数。,运行情况:2,3,Result=8,小结:任何有意义的递归调用总是由两部分组成:即递归方式与递归终止条件。,if(n=0)/*递归终止条件*/return(1);,2023/10/6,程序设计基础(C语言)wh,48,6.4 作用域和存储类型,变量是对程序中数据的存储空间的抽象,变量的属性数据类型:变量所持有的数据的性质(操作属性)存储属性存储器类型:寄存器、静态存储区、动态存储区生存期:变量在某一时刻存在 静态变量与动态变量作用域:变量在某区域内有效 局部变量与全局变量,变量的存储类型 auto 自动型 register 寄存器型 static 静态型 extern 外部型,变量定义格式:存储类型定义符 数据类型 变量名表;,如:int sub;auto int x,y,z;register int n;static float a,b;,2023/10/6,程序设计基础(C语言)wh,49,6.4 作用域和存储类型,6.4.1 局部变量及其存储类型,定义,在 函数 或 复合语句 内部定义的变量称为 局部变量。,说明主函数main中定义的变量也只在主函数中有效,其它函数不能引用;不同函数中可以使用相同名字的变量,它们代表不同的对象,占用不同的内存单元,互相独立;形式参数也是局部变量;可以在复合语句中定义变量,其作用域只是本复合语句。,2023/10/6,程序设计基础(C语言)wh,50,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的作用范围,2023/10/6,程序设计基础(C语言)wh,51,举 例,#include”stdio.h”void main()int p,q;int x;x=p+q;,x 的有效范围,p、q的有效范围,2023/10/6,程序设计基础(C语言)wh,52,6.4 作用域和存储类型,6.4.1 局部变量及其存储类型,1.自动存储变量 auto,自动存储变量 在函数或复合语句中定义和说明的变量,通常称为自动变量。自动变量前可以冠以“auto”,若变量前不加任何存储类别说明,则按缺省规则都为自动存储类别的变量。,作用域:自动变量通常是局部变量,它的作用域仅限于定义它的那个函数或复合语句。它的可见性与生存期和作用域相同。,2023/10/6,程序设计基础(C语言)wh,53,【例6_18】不同函数中的同名变量,#include stdio.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,#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”,a);,运行结果:da=1 data:a=199 main:a=101,2023/10/6,程序设计基础(C语言)wh,54,【例6_18】不同函数中的同名变量,#include stdio.hvoid main()int a;a=10;printf(“ma=%d,%xn,a,运行结果:ma=10,ffdcda=404,ffd6daa=405,ffd6data:a=199,ffd6main:a=110,ffdc,2023/10/6,程序设计基础(C语言)wh,55,6.4 作用域和存储类型,6.4.1 局部变量及其存储类型,2.静态局部变量 static,如果希望在函数调用结束后仍然保留函数中定义的局部变量的值,则可以将该局部变量定义为静态局部变量。静态局部变量前可以冠以“static”,例如 static int t,s;,说明:静态局部变量的作用域在定义它的函数内部,它的值在函 数调用结束后并不消失,但其他函数仍然不能访问它。静态局部变量赋初值是在编译过程中进行的,且只赋一次 初值。而且连续保留上一次函数调用时的结果。静态局部变量的默认初值数值型为0,字符型为Null,2023/10/6,程序设计基础(C语言)wh,56,【例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=1,a=2,a=3,2023/10/6,程序设计基础(C语言)wh,57,#include int func(int a,int b)static int m=0,i=0;i+=m+1;m=i+a+b;return(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*,6,p2=,13,2023/10/6,程序设计基础(C语言)wh,58,6.4 作用域和存储类型,6.4.1 局部变量及其存储类型,3.寄存器变量 register,为提高程序的运行速度,可将使用十分频繁的局部变量说明为寄存器变量,即在局部变量前冠以register,告知编译系统将其存储在CPU的寄存器中,void test_r(register int n)register char c;.,说明:变量的存储类型为寄存器变量时,auto说明符可省,冠以register说明符即可寄存器变量的使用与机器的硬件特性有关,有一些限制:如寄存器变量的个数;它只适用于自动变量和函数的形参;它的类型只能是char、short int、unsigned int、int和指针型;不允许对寄存器变量取地址等。Turbo C中寄存器变量只能用于整型和字符型,且限制最多只允许定义两个 寄存器变量。一旦超过,系统就自动地将其余的作为非寄存器变量来处理。,2023/10/6,程序设计基础(C语言)wh,59,i的作用范围,【例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!=2,3!=6,4!=24,i、f的作用范围,5!=120,2023/10/6,程序设计基础(C语言)wh,60,【例6_21】编一程序,输入10名学生的成绩,并求出平均成绩,#include stdio.h float ascore(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”,i的作用范围,i的作用范围,2023/10/6,程序设计基础(C语言)wh,61,6.4 作用域和存储类型,6.4.2 全局变量及其存储类型,定义,一个源程序文件可以包含一个或若干个函数。在函数之外定义的变量称为全局变量或全程变量(又称外部变量)。,全局变量与局部变量的区别:全局变量在函数之外定义,局部变量在函数之内定义;局部变量在本函数之内有效,全局变量从定义变量的位置开始到本源文件结束均有效。编译时全局变量分配在静态存储区,而局部变量则不一定。,2023/10/6,程序设计基础(C语言)wh,62,【例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(”%4d”,a*b);printf(”n”);,2023/10/6,程序设计基础(C语言)wh,63,6.4 作用域和存储类型,6.4.2 全局变量及其存储类型,1.外部变量 extern,外部变量 没有说明为static的全局变量,其存储类型都是外部的,统称为外部变量。外部变量说明extern 数据类型 变量表;,注意:凡在函数外定义的全局变量,按缺省规则可以不写说明extern,但在函数体内说明其后所定义的全局变量时,要冠以extern。若一个文件要引用另一个文件中的全局变量,应该在需要引用该 变量的文件中,用 extern说明该变量为外部的全局变量。,2023/10/6,程序设计基础(C语言)wh,64,【例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”);,extern int a;/*说明外部变量*/,extern只能用来说明变量,而不能用来定义变量。,2023/10/6,程序设计基础(C语言)wh,65,例如 在不同的文件中引用外部变量,文件f1.c的内容:#include“f2.c”int x;/*外部变量定义*/main()int sum,y;scanf(“%d”,2023/10/6,程序设计基础(C语言)wh,66,6.4 作用域和存储类型,6.4.2 全局变量及其存储类型,2.静态外部变量 static,静态全局变量一定是在本文件中定义的全局变量,其存储类型说明符是static。静态全局变量的作用域是其定义点开始到该文件的结束,在本文件外不能访问。这种全局变量起到一个屏蔽作用。也可以对函数定义成静态的,来限制函数的作用域。,静态外部变量与外部变量的相同与区别:两者都是在静态存储区中分配单元;外部变量不仅在本函数之内使用,还可以用于其他函数,但静态外部变量则不能用于其他函数;,2023/10/6,程序设计基础(C语言)wh,67,例如 下面对静态全局变量的引用是错误的:,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说明,也无法使用该变量。,2023/10/6,程序设计基础(C语言)wh,68,6.5 内部函数和外部函数,C语言程序系统由若干个函数组成,这些函数既可在同一文件中,也可分散在多个不同的文件中,根据函数能否被其它源文件调用,可将它们分为内部函数和外部函数。,2023/10/6,程序设计基础(C语言)wh,69,6.5 内部函数和外部函数,6.5.1 内部函数(静态函数),如果一个函数只能被本文件中其它函数所 调用,称为内部函数(或静态函数)。定义时在函数类型前加static:static 类型标识符 函数名,static float hust(int a,int b),函数hust的作用范围仅局限于定义本文件,而在其它文件中不能调用此函数。,2023/10/6,程序设计基础(C语言)wh,70,6.5 内部函数和外部函数,6.5.2 外 部 函 数,外部函数在函数定义的前面冠以extern说明符的函数,称为外部函数。定义外部函数 extern 类型标识符 函数名,说明:在定义函数时省去了extern说明符时,则隐含为外部函数。在需要调用外部函数的文件中,应该用extern说明所用的函数 是外部函数。,2023/10/6,程序设计基础(C语言)wh,71,【例6_24】输入一个字符,将已知字符串中的该字符删除,要求用外部函数实现。,/*file1.c*/#include stdio.h“void main()extern enter_string(char str80);extern delete_string(char str,char ch);extern print_string(char str);char c;static char str80;enter_string(str);scanf(”%c”,/*file2.c*/#include“stdio.h“/*输入字符串*/extern enter_string(char str80)gets(str);,/*file3.c*/#include stdio.h“/*删除给定的字符*/extern delete_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,c,abcdefg,2023/10/6,程序设计基础(C语言)wh,72,上机操作过程:,方法一:(1)在file1.c文件开头加入如下内容#include”file2.c”#include”file3.c”#include”file4.c”(2)对file1.c文件进行编译、连接、运行。,方法二:分别对4个文件进行编译得到四个目标文件(.obj文件)。用link功能将四个目标文件连接起来:在MS C系统上用命令:link file1+file2+file3+file4 执行结果生成一个可执行文件(.exe文件),2023/10/6,程序设计基础(C语言)wh,73,6.6 模块化程序设计,在程序设计时,如果待解决的问题比较简单,所编制的程序又不大,可将整个程序放在一个模块中。但对大而复杂的设计任务,不可能由1个人用1个程序来实现。,2023/10/6,程序设计基础(C语言)wh,74,6.6 模块化程序设计,6.6.1 模块化程序设计方法的指导思想,基本思想:将一个大的程序按功能分割成一些小模块。,开发方法:自顶向下,逐步求精。,特点:各模块相对独立、功能单一、结构清晰、接口简单。控制了程序设计的复杂性。提高元件的可靠性。缩短开发周期。避免程序开发的重复劳动。易于维护和功能扩充。,2023/10/6,程序设计基础(C语言)wh,75,C语言是模块化程序设计语言,C是函数式语言必须有且只能有一个名为main的主函数C程序的执行总是从main函数开始,在main中结束函数不能嵌套定义,可以嵌套调用,2023/10/6,程序设计基础(C语言)w