《模块化程序设计》PPT课件.ppt_第1页
《模块化程序设计》PPT课件.ppt_第2页
《模块化程序设计》PPT课件.ppt_第3页
《模块化程序设计》PPT课件.ppt_第4页
《模块化程序设计》PPT课件.ppt_第5页
已阅读5页,还剩140页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第四章 模块化程序设计 主讲人:韩维良 * C语言程序设计 C语言支持模块化程序设计的功能: (1) C语言用函数组织程序: 一个程序由一个或多个源程序文件组成; 每一个源程序文件就是一个程序模块; 每一个程序模块由一个或多个函数组成。 程序设计的任务就是设计一个个函数,并且确定它们之 间的调用关系。 在设计函数时要使每个函数都具有各自独立的功能和明 显的界面。 C语言程序设计 (2) 通过给变量定义不同的存储类别,控制模块内部 及外部的信息交换。 (3) 具有编译预处理功能,为程序的调试、移植提供 了方便,也支持了模块化程序设计。 C语言程序设计 第一节 函 数 一、设计C语言程序就是设计函数 用C语言设计程序,任务只有一种,就是编写函数,至 少也要编写一个main函数。 执行C程序也就是执行相应的main函数。即从main函数 的第一个前花括号开始,依次执行后面的语句,直到最后的 后花括号为止。 C语言程序设计 模块化程序设计有一个原则:就是每个模块的规模 一般不能太大(一般要控制在4060行之间),以便于阅 读,便于检查其中的错误。 在C语言中,减少主函数规模的一项基本措施就是通 过调用其它函数来实现主函数需要的一些功能。 main(void)main(void) f1(); f1(); f2(); f2(); return 0;return 0; 操操 作作 系系 统统 f1()f1() f11(); f11(); f2()f2() f21(); f21(); f22();f22(); f11()f11() f21()f21() f22()f22() 一般C语言程序的执行过程 main()main() f1()f1()f2()f2() f22()f22()f21()f21()f11()f11() 参数参数 参数参数参数参数 参数参数 参数参数返回返回 返回返回 返回返回 返回返回 返回返回 程序结构图 大学信息管理系统 办公室管理办公室管理 图书管理图书管理 设备管理设备管理 教务管理教务管理 科研管理科研管理 人事管理人事管理 财务管理财务管理 后勤管理后勤管理 学籍管理学籍管理 成绩管理成绩管理 排课管理排课管理 C语言程序设计 二、函数结构 一个C语言函数的结构形式如下: 函数头 函数体 C语言程序设计 1. 函数头 函数头结构: 函数类型 函数名(形式参数表列) 一个函数的函数头的结构如下: (1)函数类型:指定函数值的类型,即函数返回值 的类型。 (2)函数名:必须采用合法的用户标识符。 (3)圆括号:是“函数运算符”,表示进行函数运 算,函数运算符具有很高的运算优先级别。 C语言程序设计 (4)形式参数表:由写在一对圆括号(函数运算符)中 的一系列参数组成。 每一个参数由一个类型符和一个参数名组成。参数名 是合法的标识符。 函数可以没有参数,这时在函数运算符内写一个 “void”,也可以空白,但小括号不能省略。 C语言程序设计 2. 函数体 函数体由一些语句组成。 主要是三种类型的语句: 声明语句:声明在函数中要使用的变量等程序实体。 可执行语句:用来实现函数的功能,包括若干流程控制 语句和表达式语句。 return语句:停止本函数的执行,使流程返回到调用处 。 C语言程序设计 编译器将函数分为三类进行处理: 纯粹计算型函数,如sqrt()和sin()。将返回一个计 算结果。 完成一项具体工作,返回完成的成败。如printf() 执行成功时,返回显示的字节数;失败时,返回一个负整 数。 函数不产生返回值,其类型应定义为void。 C99规定,对于非void类型的函数,必须使用有返回值 的return语句。 int absolutevalue (int x) /* 绝对值函数 */ return (x=0?x:-x); void spc (int n) /* n空格函数 */ int i; for (i=0; i10) return (2*n+3); else return; 平行的两个返回语句,返回值不平行的两个返回语句,返回值不 同,编译时可能出现警告错误,同,编译时可能出现警告错误, 但不影响使用,结果不可预测。但不影响使用,结果不可预测。 C语言程序设计 3. 函数中变量的作用域 作用域指的是一个程序段中的变量的作用范围,在一个 函数中定义的变量只在本函数中有效,在其它函数中不能使 用这个变量。 因此说,该变量的作用域是它所在的函数(从定义该变 量的行开始到函数末尾)。即使在不同的函数中定义了同名 的变量,它们也是指不同的变量。 #include int func(int x) x=5; return x+3; int main(void) printf(“x=%dn“,x); return 0; 这个程序企图在这个程序企图在mainmain函数中使用函数中使用 funcfunc函数中的变量函数中的变量x x。编译这个程序。编译这个程序 ,系统将给出如下编译错误:,系统将给出如下编译错误: c(12) : error C2065: x : c(12) : error C2065: x : undeclared identifierundeclared identifier ( (未声明的标识符未声明的标识符 ) ) C语言程序设计 4. 空函数 空函数是一个不产生任何有效操作的函数,但它却是一 个合法的C函数。 例如函数 void null(void) 就是一个空函数。 空函数多使用在模块化程序的设计或测试中。有一些函 数还未编写,可用空函数进行调试,这样就可以调试程序的 其它部分,等以后再逐步补上。 C语言程序设计 三、函数定义与函数声明 1、函数定义 函数定义是按照C语言的语法规则引入新的函数,并提 供如下信息: 函数的返回值类型(如果有); 参数的个数及类型和名称; 调用函数时要执行的代码; 函数的有效性(不能嵌套定义)。 C语言程序设计 函数的定义 类型说明符 函数名(类型名 形式参数1 , 类型名 形 式参数2 , ) /* 函数的首部 */ 说明部分 /* 函数体 */ 语句部分 C语言程序设计 其中类型说明符和函数名部分共称为函数头。 类型说明符即本函数的类型,实为函数返回值的类型。 函数名是由用户定义的标识符,函数名后有一个括号, 其内容为形参表。 在形参表中给出的参数称为形式参数,即形式参数变量 的定义,各参数定义之间用逗号间隔。在进行函数调用时, 主调函数将赋予这些形式参数实际的值。 当形参表中无参数时,括号不可少。 中的内容称为函数体。 在函数体中也有类型说明, 这是对函数体内部所用到 的变量的类型说明。 注意:函数不能嵌套定义。 void fun1() int fun2() 而应该为如下形式而应该为如下形式: : void fun1()void fun1() int fun2()int fun2() C语言程序设计 2、函数的返回值及其类型 (1) return语句 函数的返回值通过函数体内的return语句实现。 return 返回值表达式 ; 或 return (返回值表达式); 如果没有返回值,格式中的左、右圆括号可以省略,即 写为: return ; 功能:返回调用函数,并将“返回值表达式”的值带给 调用函数。 C语言程序设计 说明: 1)函数的返回值只能有一个。 2)当函数中不需要指明返回值时,可以写成: return; 也可以不写。函数运行到右花括号自然结束。 3)一个函数体内可以有多个返回语句,不论执行到哪一 个,函数都结束,回到主调函数。 4)当函数没有指明返回值,即return; 或没有返回语句 时,函数执行后实际上不是没有返回值,而是返回一个不确 定的值,有可能给程序带来某种意外的影响。 C语言程序设计 (2)函数返回值的类型 函数定义时的类型就是函数返回值的类型。从理论上, C语言要求函数定义的类型应当与返回语句中表达式的类型 保持一致。当两者不一致时,系统自动进行转换,将函数返 回语句中表达式的类型转换为函数定义时的类型。 如果定义函数缺省函数类型,则系统一律按int型处理 。 C语言程序设计 3、函数声明 函数声明是对所用到的函数的特征进行必要的声明。 编译系统以函数声明为检测依据:检测形参与实参类型 是否一致,返回值的类型是否正确,以保证调用表达式与函 数之间的参数正确传递。 声明语句提供的必要信息包括:函数名,函数的类型, 函数参数的个数、排列次序以及每个参数的类型。 C语言程序设计 函数的定义可以按任意的次序,但在主调函数中,要调用 另一个函数,则需要对被调函数先做声明(或者说明)。 所谓声明,就是把函数的类型、函数的名称、函数形参的 类型及个数、顺序通知编译系统,便于在调用时进行检查。 函数声明的一般形式: 函数类型 函数名(参数类型1 , 参数类型2) ; 或 函数类型 函数名(参数类型1 参数名1 , 参数类型2 参数名2) ; C语言程序设计 说明: (1)如果被调函数的返回值为int类型,则不管被调函数 位置如何均不需要在主调函数中说明。 (2) 如果被调用函数的声明放在源文件的开头,则该声 明对整个源文件都有效。 (3) 如果被调用函数的声明是在调用函数定义的内部, 则该声明仅对该调用函数有效。 C语言程序设计 (4) 在函数调用中,有下面几种情况可以省略声明: a. 如果调用函数和被调用函数是在同一个源文件中, 而且被调用函数的定义是在调用函数之前。 b. 函数的返回值是整数或字符。 c. 所有被调用函数的声明都是在源文件开头。 d. 如果被调用函数不是在源文件开头,而是在源文件 中间且在所有函数之外某处被声明时,则在被声明之后引用 它时,不必再声明,但在被声明之前引用它时,需要对其进 行声明。 (5) 如果调用函数和被调用函数的定义是在同一源文件 中,应该先说明或定义被调用函数。 设有一函数的定义为: double func (double a, int b, char c) /* 函数体*/ 与之相应的函数声明应为: double func (double x, int y, char z); /* 注意末尾的分号 */ 33C语言程序设计 例求二实数之和 main ( ) float add(float,float); float a, b, c; scanf(“%f%f“, c=add(a, b); /*函数表达式调用形式*/ printf (“sum= %f“;c); float add( float x, float y) float z; z=x+y; return z; 说明:调用过程中参数的对应关系。 C语言程序设计 例 定义一个求两个整数中极大值的max()函数。 /*功能:求2个整数中的较大数 */ /*形参:2个,整型 */ /*返回值: 2个整数中的较大数 */ int max(int n1,int n2) /*函数定义 */ int z; z= n1 n2 ? n1 : n2; return (z); C语言程序设计 void main( void ) int max(int n1, int n2); /*对被调函数说明*/ int num1,num2; printf(“input two numbers: “); scanf(“%d%d“, printf (%f+%f=%fn, x,y, add(x,y); float add (unsigned int a, unsigned int b) printf(a=%u, b=%un, a,b); return (a+b); 分析结果为什么错分析结果为什么错 误?误? 如何改正?如何改正? 3、传值调用的虚实结合过程 程序进行编译时,并不为形式参数分配存储空间。 只有在被调用时,形式参数才临时地占有存储空间 ,其过程如下: (1)调用开始,系统为形参开辟一个临时存储区 ,形参与实参各占一个独立的存储空间。 (2)将各实参之值传递给对应形参,形参得到了 实参的值。这种虚实结合方式称为“值结合”。 (3)函数返回时,临时存储区也被撤销。 特别注意:在C程序中实参与形参是传值调用(call by value) 的特点。即实参与形参是“单向的值传递” 即函数中对形参变量的操作不会影响到调用函数中的实参 变量,即形参值不能传回给实参。 #include void swap (int x, int y); int main(void) int a=3, b=5; swap (a,b); printf (a=%d, b=%dn, a,b); return 0; void swap (int x, int y) int temp; temp=x, x=y, y=temp; /* 交换变量的值 */ printf(x=%d,y=%dn,x,y); 执行结果: x=5,y=3 a=3,b=5 企图交换变量 a,b的值,没 有成功 五、函数的嵌套调用 语言的函数定义是互相平行、独立的 函数不能嵌套定义 可以嵌套调用函数 调用一个函数的过程中,又可以调用另一个函数。 函数的嵌套调用的过程 main函数 调用a函数 结束 a函数 调用b函数 b函数 C语言程序设计 例一个偶数为两个素数之和。 德国数学家哥德巴赫(GoLdbach)在1725年写给欧拉 (Euler)的信中写下了以下猜想:任何不小于6的偶数都是两 个素数之和(俗称为1+1)。如633,1257等等。 两个多世纪过去了,这一猜想既无法证明也没被推翻 。试设计程序验证这一猜想是否成立。 对于一个偶数,找出一个小于它的数,判断是否是素 数,如果是就计算该偶数与该素数的差并判断它是否是素 数。如果两者都是素数则猜想得到验证。 问题表现为:任意输入一个偶数,可将其分解为两个素 数之和。 50C语言程序设计 #include main() void even(int x); int a; printf(“请输入一个偶数:”); scanf(“%d”, if (a%2=0) even(a); /*函数调用语句*/ else printf(“所输入的数不是偶数!n”); 51C语言程序设计 void even(int x) int isprime(int a); int i; for(i=2;i #define IN 1 #define OUT 0 int countword(); main() int n; n=countword(); printf(“单词数为:%dn”,n); 55C语言程序设计 int countword() /*没有形参*/ int c,nw,state; state=OUT; nw=0; while(c=getchar()!=) if(c= |c=n|c=t) state=OUT; else if(state=OUT) state=IN; nw+; return(nw); 六、递归函数 一个函数可以调用另一个函数。 递归函数一个函数自己调用自己(直接地或间接 地调用自己)。 前者称为直接递归调用函数,后者称为间接递归调用 函数。 1.递归调用次数有限 2.程序执行有规律 3.有结束调用的条件 C语言程序设计 递归调用是指一个函数直接或间接地调用自己。这种函 数称为递归函数。自己调用自己,即要解决一个问题,转化 为一个用同样的方法解决的新问题,只是参数在不断地递增 或者递减。 在递归调用中,主调函数又是被调函数。执行递归函数 将反复调用其自身。 对于一些特定的问题,用递归算法来解决,可以简化问 题的复杂程度。 *58 *59 C语言程序设计 例:用递归调用求n!。 要用递归法解决此问题,必须明确两个问题: 、递归算法 n!=n*(n-1)! (n-1)!=(n-1)*(n-2)!; 求n的阶乘的问题,转化为用同样的方法求(n-1)的阶乘。 如:4!4*3! 3!3*2! 如果编写成一个函数,则调用如下: f(n)=n*f(n-1); 不断地自己调用自己。 C语言程序设计 、递归终结条件 递归到一定的程度后,必须终止。 如求阶乘时,当求到1!时,必须停止递归。 f(1)=1 这一条是必须的,否则将会没完没了的进行下去。 通常用条件判断, 满足某种条件后就不再作递归调 用,然后逐层返回。 C语言程序设计 例如有函数f如下: int f(int x) z=f(x1); return z; 上页中的函数是一个递归函数。 但是运行该函数将 无休止地调用其自身,这当然是不正确的。为了防止递归 调用无终止地进行, 必须在函数内有终止递归调用的手 段。 C语言程序设计 例 用递归法计算n!。 #include long f(int n) long y; if(n1) y=n*f(n-1); else y=1; return(y); 64C语言程序设计 main() int n; long y; printf(“input a inteager number:”); scanf(“%d“, y=f(n); printf(“%d!=%ldn“,n,y); 程序运行情况如下: input a inteager number: 5 5!=120 C语言程序设计 程序说明: 程序中给出的函数f是一个递归函数。主函数调用f 后即进入函数f执行,如果n main() int n; long fib(int); /*第40项的值很大*/ printf(“请输入项数:”); scanf(“%d”, printf(“第%d项的值为:%ldn”,n,fib(n); 69C语言程序设计 long fib(int n) long result; if(n=1|n=2) result=1; else result=fib(n-1)+fib(n-2); return result; 第二节 变量的存储属性 变量是对程序中数据存储的抽象。 C语言程序中变量都有类型,数据类型是变量的运算属 性的抽象,决定了该变量的取值范围和可以施加的运算种 类。 除此之外,变量还有一些属性,例如: 一个变量在程序的哪个范围内是可以使用的变量的 可用域; 它什么时候生成以及什么时候被撤消变量的生存 期; 它存储在什么哪种类型的存储器中以及用什么机制进行 存储变量的存储区。 这些都称为变量的存储属性。 一、变量的作用域与生存期 在函数中形参变量只在被调用期间才分配内存单元,调用 结束立即释放。形参变量只有在函数内才是有效的,离开该函 数就不能再使用了。 如:货币的使用范围,校园卡的使用范围。 1. 局部变量和全局变量 变量的可用域是指一个变量在程序的哪个域内才是可以被 识别的,也称为可见(或可用)的。 变量可分为两种: 全局可用全局变量 局部可用局部变量。 C语言程序设计 局部变量:在一个函数或者复合语句(如函数体、循环 体)内部定义的变量是局部变量,它只在该函数或者复合语 句范围内有效。而在其它函数内不能使用。 只有在包含变量定义的函数内部,才能使用被定义的变 量,在此函数之外就不能使用这些变量了。又称为内部变量 。 例如: int f1(int a) /*函数f1*/ int b,c; /*a,b,c作用域:仅限于函数f1()中*/ C语言程序设计 int f2(int x) /*函数f2*/ int y,z; /*x,y,z作用域:仅限于函数f2()中*/ main() int m,n; /*m,n作用域:仅限于函数main()中*/ 由于局部变量只在一个局部范围中使用,因此在不同的函数 中可以定义同名的局部变量,它们互不干扰,各自分配不同的独 立存贮单元。这种特性便于进行模块化设计,不同的模块由不同 的程序员设计,各模块中使用的变量名由用户自己确定,即便相 同也不会彼此影响。 75C语言程序设计 #include main() void fun1(); void fun2(); int x=1; printf(“x=%dn”,x); int x=3; printf(“x=%dn”,x); printf(“x=%dn”,x); fun1(); printf(“x=%dn”,x); fun2(); printf(“x=%dn”,x); fun1(); C语言程序设计 fun1() int x=5; printf(“x=%dn”,x); fun2() int x=7; printf(“x=%dn”,x); 说明: 四个X分别分配了不同的存贮单元。 同一函数的两次调用分配了不同的单元。 #include #include int main(void)int main(void) /* printf(“a1=%d“,a); */* printf(“a1=%d“,a); */ int a=3;int a=3; printf(“a2=%d“,a); printf(“a2=%d“,a); int b=5; int b=5; printf(“b1=%d“,b); printf(“b1=%d“,b); /* printf(“b2=%d“,b); */ /* printf(“b2=%d“,b); */ printf(“a3=%d“,a); printf(“a3=%d“,a); return 0; return 0; b的作用域 a a的作用域的作用域 则运行可以得到如则运行可以得到如 下结果:下结果: a2=3a2=3 b1=5b1=5 a3=3a3=3 C语言程序设计 全局变量:也称为外部变量,是在函数外部定义的变量 ,作用域为从定义全局变量位置开始到源程序结束,是多个 函数间进行数据传递的一种手段。 全局变量可以在其作用范围内,由各函数所共用。 在函数中使用全局变量,一般应作全局变量说明。 只 有在函数内经过说明的全局变量才能使用。 全局变量的说明符为extern。 但在一个函数之前定义 的全局变量,在该函数内使用可不再加以说明。 C语言程序设计 例如: int a,b; /*外部变量*/ void f1() /*函数f1*/ float x,y; /*外部变量*/ int f2() /*函数f2*/ C语言程序设计 main() /*主函数*/ /*全局变量x,y作用域 全局变量a,b作用域*/ 从上例可以看出a、b、x、y 都是在函数外部定义的外 部变量,都是全局变量。但x,y 定义在函数f1之后,而在f1 内又无对x,y的说明,所以它们在f1内无效。 a,b定义在源 程序最前面,因此在f1,f2及main内不加说明也可使用。 81C语言程序设计 #include int a=3,b=5; main() void fun(); printf(“a=%d,b=%dn”,a,b); fun(); printf(“a=%d,b=%dn”,a,b); void fun() int c; c=a;a=b;b=c; printf(“a=%d,b=%dn”,a,b); C语言程序设计 【例】输入长方体的长宽高l,w,h。求体积及三个面 x*y,x*z,y*z的面积。 int s1,s2,s3; int vs( int a,int b,int c) int v; v=a*b*c; s1=a*b; s2=b*c; s3=a*c; return v; C语言程序设计 main() int v,l,w,h; printf(“ninput length,width and height: “); scanf(“%d%d%d“, v=vs(l,w,h); printf(“v=%d s1=%d s2=%d s3=%dn“,v,s1,s2,s3); 程序运行结果如下: input length,width and height:4 5 6 v=120 s1=20 s2=30 s3=24 C语言程序设计 程序说明: 本程序中定义了三个外部变量s1,s2,s3,用来存放三个 面积,其作用域为整个程序。函数vs用来求正方体体积和三 个面积,函数的返回值为体积v。由主函数完成长宽高的输 入及结果输出。 由于语言规定函数返回值只有一个,当需要增加函数 的返回数据时,用外部变量是一种很好的方式。本例中,如 不使用外部变量,在主函数中就不可能取得v,s1,s2,s3四个 值。而采用了外部变量,在函数vs中求得的s1,s2,s3值在 main中仍然有效。因此外部变量是实现函数之间数据传输的 有效手段。 C语言程序设计 当在函数外定义了一个全局变量后,定义点之后的函数 都可以使用该变量. 当全局变量的值在一个函数中改变后,另一个函数使用 的就是改变后的值. 从定义开始到程序结束,全局变量自始至终占用存储空 间. 全局变量的使用使函数间的联系加强,与程序设计”低 耦合”的原则相违背,所以很少使用。 例同名局部变量 #include int main(void) int a=3; printf(“a1=%d“,a); int a=5; printf(“a2=%d“,a); return 0; 例演示全局变量 #include void a() int a=1; printf(“a1=%dn“,a); printf(“x1=%dn“,x); int x=3; * 定义外部变量 */ void b() printf(“x2=%dn“,x); int main(void) a(); b(); printf(“x3=%dn“,x); return 0; 例演示全局变量与局部变量同名 #include int x=3; /* 定义外部变量 */ int main(void) int x=5; printf(“x=%dn“,x); return 0; 2. 动态变量与静态变量 运行中的程序,在内存中被分成代码区和数据区两大 部分。 数据区又分为静态存储区、自动存储区和动态分配区 三部分。 自动存储区是按栈组织的存储区。 除特别声明的外,局部变量通常被存放在栈区。 这些变量在进入所在的块时被创建,所在的块结束时 被撤销,其值不再保留。并且,变量必须有程序员显式地 进行初始化,否则它们的初始值是不确定的。 静态存储区是在程序编译时就分配的存储区。 分配在静态存储区的变量在程序开始执行时被创建并自 动初始化(数值变量被初始化为0),当程序结束时才被撤 销。 所以常称静态变量的生存期是永久的。 全局变量就是被分配在静态存储区的。 /* 企图交换两个变量的值*/ #include void swap(void);/* 说明函数 */ int a=3, b=5;/* 声明外部变量 */ int main(void) printf (“a=%d, b=%dn“,a, b); swap(); printf (“a=%d, b=%dn“, a,b); return 0; void swap(void) int c;/* 声明自动变量*/ c=a; a=b; b=c;/* 交换变量的值 */ 二、C语言中变量的存储类型 根据可用域和生存期,变量有4种存储类型: 局部自动类型,在函数内部用标识符auto或register 声明。 静态局部类型,在函数内部,使用static声明。 静态全局类型,在函数外部,使用static声明,也称 静态外部变量。 全局类型,不需要标识符声明。在函数外部直接声明 即可,通称外部变量。 1、auto存储类型和register存储类型 使用auto声明的变量是局部变量,编译器将其分配在自 动存储区。 其格式为: auto 数据类型变量名=初值表达式,; 其中方括号表示可省略,省略auto,系统隐含认为此变 量为auto。 函数的参数(形参)也是一种自动变量。 C语言程序设计 自动变量的类型说明符为auto; 语言规定,函数内凡未加存储类型说明的变量均视为 自动变量,也就是说自动变量可省去说明符auto。 在前面所学的程序中定义的变量凡未加存储类型说明符 的都是自动变量。 C语言程序设计 例如: int a,b,k; char c; 等价于: auto int a,b,k; auto char c; C语言程序设计 自动变量的特点: 自动变量的作用域仅限于定义该变量的函数或复合语句 内。 自动变量存贮在自动存贮区,只有在使用它,即定义该 变量的函数被调用时才给它分配存储单元,开始它的生存期 。函数调用结束,释放存储单元,结束生存期。因此函数调 用结束之后,自动变量的值不能保留。 未初始化时,自动变量的值是不确定的。 由于自动变量的作用域和生存期都局限于定义它的函数 或复合语句内,因此不同的函数中允许使用同名的变量而不 会混淆。 C语言程序设计 寄存器变量的说明符是register。 存放在CPU的寄存器中,使用时,不需要访问内存,而 直接从寄存器中读写, 这样可提高访问效率。 特点:加快运算速度,函数运行完即消失、使用有限。 如定义一个频繁使用的变量为寄存器类型: register int i; C语言程序设计 2、静态局部类型 类型说明符:static,属于静态存储方式; 在一个函数内部,可以用static定义一个变量,称为静 态局部变量。其作用域仍在定义它的函数内部,但其生存期 却程序运行期。 函数调用结束后,并不释放所占用的存贮空间(总是占 用固定的存贮空间),在程序运行期间,始终存在,但除了 定义它的函数以外,别的函数不能使用。整个程序运行结束 后,才释放占用的空间。 C语言程序设计 静态局部变量的特点: (1)静态局部变量在每次调用函数结束后能够保留调 用结束后的值不变,留待下一次调用,变量值具有继承性。 (2)静态局部变量只限于被本函数使用,不能被其他 函数使用 (3)静态局部变量属于静态存储类别,在整个程序运 行期间都不释放;而动态存储变量属于动态存储类别,函数 调用结束即释放,再次调用又将重新分配空间。 (4)在定义静态局部变量时,如果不赋初值,系统自 动赋值为0或空字符(对字符型变量)。 99C语言程序设计 #include func() static int b=10; b=b+2; return b; main() int i; for(i=1;i void increment(void); int main(void) increment ( ); increment ( ); increment ( ); return 0; void increment(void) int x=0; /*auto*/ x+; printf (%dn,x); 运行结果:运行结果: 1 1 1 1 1 1 #include void increment(void); int main(void) increment ( ); increment ( ); increment ( ); return 0; void increment(void) static int x=0; /*使用了static说明符 */ x+; printf (%dn,x); 运行结果:运行结果: 1 1 2 2 3 3 3、静态全局类型 在多文件程序中,用static声明外部变量,使该外部变 量的作用域仅限于所在的文件,而不用static声明的外部变 量的作用域为整个程序。 例如:某个程序中要用到大量函数,而有几个函数需要 共同使用几个全局变量时,可以将这几个函数组织在一个文 件中,而将这几个全局变量用static定义为静态的,以保证 它们不会与其他文件中的变量发生名字冲突,保证文件的独 立性。 static unsigned int r; int random(void) r=(r*123+59)%65536; return(r); /*产生r的初值*/ unsigned randomstart(unsigned int seed)r=seed; #include int main(void) int i, n; printf (“please enter the seed:“); scanf(“%d“, randomstart(n); for(i=1; i void gx(), gy (); void main(void) extern int x,y; /*声明x,y是外部变量,作用域扩充至此*/ printf (“1:x=%dt y=%dn“, x, y); y=246; gx(); gy(); void gx() extern int x, y; /*声明x,y是外部变量*/ x=135; printf(“2:x=%dt y=%dn“, x, y); int x, y; /*定义x,y是外部变量 */ void gy() printf(“3:x=%dt y=%dn“, x, y); (2)利用声明语句将作用域扩大到其他文件建立对 象的外部链接 假设一个程序由两个以上的文件组成。当一个全局变量 定义在文件file1中时,在另外的文件中使用extern声明, 可以通知编译系统一个信息:“此变量到外部去找”。或者 说在链接时,告诉链接器:“到别的文件中找这个变量的定 义”。 * file1.c */ #include int x, y; char ch; void main(void) x=12; y=24; f1(); printf(“%cn“, ch); * file2.c */ extern int x,y; extern char ch; f1( ) printf (“%d, %dn“, x,y); ch=a; (3) 全局变量的副作用 如果没有外部变量,函数只能通过参数与外界发生数据 联系,有了外部变量以后,增加了一条与外界传递数据的渠 道,但也会产生一些副作用. /* 例能否输出5行 *?*/ #include int i; void main(void) void prt(); for(i=0; i 宏定义 如:#define case break; case 注释 好的头文件不能包含以下内容: 一般函数定义 数据定义 如: int a; 常量聚集定义 如: const tbl=/* */; 用户头文件是由用户自己定义的头文件。 系统将用双引号方式进行搜索。 #include “头文件名.h“ 程序员可以用它们建立各文件之间的信息窗口。 应当注意,修改了头文件时,所有涉及该头文件的程序 都应重新编译,所以在编制头文件时应尽量考虑周全。 当使用很多头文件时,常有重复嵌入的情形发生,在这 种情形下,应防止标识符重复定义的错误。 为避免错误,应使用条件编译来测试有无重复定义。 C语言程序设计 第四节 宏定义与宏替换 编译预处理是以“#”开头的一些命令,它通知编译系统 :在进行正式编译前应当先进行一些前期工作(即编译预处 理)。 目前,C语言的编译预处理功能主要有如下一些: (1)文件包含,使用命令:#include。 (2)宏定义,使用命令:#define、#undef。 (3)条件编译,使用命令:#if、#ifdef、#ifndef、 #else、#endif、#elif、defind。 (4)提供行号信息,使用命令:#line。 (5)编译杂注,使用命令:#progma。 (6)错误信息,使用命令:#error。 在这些编译预处理中,应用最多的就是对宏的处理。 它允许程序员使用define定义并应用宏名字书写C语言 程序,同时也指示编译器在正式编译前通过宏替换,使程序 能按照C语言的语法进行编译。 一、字符串宏定义及其基本格式 define命令最简单的应用就是定义一个符号常量。 格式为: define 宏名 字符串 编译预处理时,预处理程序将把程序文件中在该宏定义 之后的所有宏名,用#define命令中定义的字符串(称为宏 体)替换,这个过程称为宏替换。 符号常数的定义就是这种宏定义的一种应用。 #define PI 3.14159265 #define RADIUS 2.0 使用宏定义的好处是: (1) 提高了程序的可读性。 如果人们看到以下语句 return (2.0*3.1415926536*2.0); 和 return (3.1415926536*2.0*2.0); 是否能很快地看出它们在计算什么呢?显然不能。 如果写成下面的形式: return (2.0*PI*RADIUS); 和 return (PI*RADIUS*RADIUS); 可以看出:这是在计算圆周长和圆面积。 使用宏定义可以提高可理解性。 (2) 易修改性好。 如要将RADIUS的值由2.0修改为3.0,只要在define 命令中修改一处便可。 而在不使用宏定义的文件中,要将3处的2.0修改为3.0 ,而且很可能也错把前一个返回语句也修改成 return (3.0*3.1415926536*3.0); (3) 宏定义可以给程序设计带来许多方便。 二、使用宏需注意的问题 (1)在#define命令中,宏名字与字符串(宏体)之间用 一个或多个空格分隔。 (2)宏名字的使用 宏名字不能用引号括起来。 如:#define “YES 1 printf(“YES“); 将不进行宏定义。 宏名中不能含有空格。 例如想用“A NAME”定义“SMISS”,而写成: #define A NAME SMISS 则实际进行的宏定义是A为宏名字,宏体是“NAME SMISS”。 C程序员一般都习惯用大写字母定义宏名字。这样的表 示方法使宏名与变量名有明显的区别,以避免混淆。此外 有助于快速识别要发生宏替换的位置,提高程序的可读性 。 不能进行宏名字的重定义。 (3)定义一个宏名字以后,就可以在后面使用这个宏名字 了,包括在后面的宏定义中使用。 例如求圆的周长和面积的程序可以改写为 #include #define PI 3.1415926 #define R 1.0 #define CIRCUM 2.0*PI*R /* 使用了前面定义的R和PI */ #define AREAPI*R*R int main(void) printf(“The circum is %f and area is %fn”,CIRCUM,AREA); /*下面是另外一种形式的宏定义: */ #include #define PI 3.14159265 #define RADIUS 1.0 #define CIRCUM return(2.0*PI* RADIUS); /*分号是return语句的一部分 */ #define AREA return(PI* RADIUS* RADIUS); double circum( ) CIRCUM double area( ) AREA int main(void) printf(“The circum is %f and area is %fn“,circum(),area(); (4)不能进行的宏替换。 不可以替换作为用户标识符中的成分。 例如在前面的例子中,不可以用“R”替换“CIRCUM” 中的“R”。 不能替换字符串常量中的成分。 举例如下: #include #define PI 3.14159265 #define RADIUS 1.0 #define CIRCUM return(2.0*PI* RADIUS); #define AREA return(PI* RADIUS* RADIUS); int main(void) printf(“The CIRCUM is %f ”, CIRCUM); printf(“ and AREA is %fn”, AREA ); 运行结果为: The CIRCUM is 6.283185 and AREA is 3.141593不会用 宏名字“CIRCUM”和“AREA”替换格式串“CIRCUM”和 “AREA”。 (5)一行中写不下的宏定义,应在前一行结尾使用一 个续行符“”,并且在下一行开始不使用空格。 例如例如 #define AIPHABET ABCDEFGHHIJKLMN#define AIPHABET ABCDEFGHHIJKLMN OPQRSTUVWXYOPQRSTUVWXY (6)宏定义可以写在源程序中的任何地方,但一定要 写在程序中引用该宏之前,通常写在一个文件之首。对多 个文件可以共用的宏定义,可以集中起来构成一个单独的 头文件。 三、撤销已定义的宏 用命令undef 可以撤销已定义的宏。 如: #define OK 1 #undef OK 在 #undef 命令行之后的范围,OK不再代表1。 *135C语言程序设计 四、带参数的宏定义 语言允许宏带有参数。在宏定义中的参数称为形式参 数,在宏调用中的参数称为实际参数。对带参数的宏,在调 用中,不仅要宏展开

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论