c语言程序设计 第6章_函数.ppt_第1页
c语言程序设计 第6章_函数.ppt_第2页
c语言程序设计 第6章_函数.ppt_第3页
c语言程序设计 第6章_函数.ppt_第4页
c语言程序设计 第6章_函数.ppt_第5页
已阅读5页,还剩96页未读 继续免费阅读

下载本文档

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

文档简介

1、C语言程序设计教程(第2版),第6章 函数,C程序的结构:,C程序结构,说明: 1、一个C程序由一个或多个源程序文件组成。对较大的程序,一般不希望全放在一个文件中,而是将函数和其他内容(如预定义)分别放在若干个源文件中,再由若干个源文件组成一个C程序。这样做可以分别编写、分别编译,从而提高效率。 (多个源文件中只能有一个是包含主函数的) 2、一个源程序文件由一个或多个函数组成。一个源程序文件是一个编译单位,即以源程序文件为单位进行编译,而不是以函数为单位进行编译。 3、一个源程序文件可以为多个C程序共用。 4、C程序的执行总是从主函数main( )开始,调用其他函数后返回到主函数,在主函数中结

2、束整个程序的运行。 main( )函数是系统定义的。,C语言是函数式语言; 必须有且只能有一个名为main的主函数,主函数main是必须的,其他函数的数目是不限的; C程序的执行总是从main函数开始,在main中结束; main函数只调用其他函数,但不能被其他函数所调用; 如果不考虑函数的功能和逻辑,其他函数没有主从关系,可以相互调用; 所有函数都可以调用库函数; 所有函数都是平行的,在定义时是相互独立的,一个函数并不从属于另一个,即函数不能嵌套定义,但可以嵌套调用。,C语言程序的总体功能的实现:通过函数的调用来实现,C语言的函数分为两类: 系统定义的标准函数,又称为库函数。由系统提供.此类

3、函数不需要用户定义,也不必在程序中作说明,只需在程序开头前用文件包含命令将包含有该函数原型的头文件包含进来即可在程序中直接调用.这些函数总的可分为输入输出函数、数学函数、字符串处理函数和内存函数等. 如: printf( )、 scanf( )、 putchar( )、 sqrt( )等。 在调用该函数之前用#include命令将库函数信息包含到本程序中。 常用的库函数请查阅附录C。,使用库函数应注意: 1、了解函数功能 2、了解函数参数的数目和顺序,及各参数意义和类型 3、函数返回值意义和类型 4、需要使用的文件包含命令,在程序的开头用#include 或#include “*.h”说明。只

4、有这样程序在编译、连接时Turboc才知道它是提供的库函数,否则,将认为是用户自己定义的函数而不能装配。 (使用printf()和scanf()这两函数时可省略),自定义函数。 按要求设计的。 C语言程序设计的核心之一:自定义函数。 按用户需求写的函数。此类函数不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明才能使用。,printstar( ) /*用户自定义的函数*/ printf(“* * * * * * * * * * * * * *n”); printsmessage( ) /*用户自定义的函数*/ printf(“ how do you do !n”);

5、 main( ) printstar( ); /*在主函数中调用自定义函数*/ printsmessage( ); /*在主函数中调用自定义函数*/ printstar( ); /*在主函数中调用自定义函数*/ 程序运行结果: * * * * * * * * * * * * * how do you do ! * * * * * * * * * * * * *,从C语言中的函数功能角度来看,可分为有返回值函数和无返回值函数: (1)有返回值函数:此类函数被调用执行完后将向调用者返回一个执行结果,称为返回值.用户定义此类函数时必须在函数定义和函数说明中明确说明返回值的类型.(若返回值是整型则定义

6、时可以省略类型) 如:sin( )、cos( )等数学函数即属于此类函数 (2)无返回值函数:此类函数用于完成某项特定的处理任务,执行完后不向调用者返回函数值.用户定义此类函数时可指定返回值的类型为“空类型”,空类型的说明符为“void”。,从主调函数和被调函数之间传送的角度来看,可分为无参函数和有参函数: (1)无参函数:此类函数在函数定义、函数说明及函数调用中均不带参数,主调函数和被调函数之间不进行参数传递。此类函数一般用来完成一组特定的功能,可以返回或不返回函数值。 注:若定义时没有返回值是“空类型”,则函数返回值是存在的。若希望函数没有返回值,则在定义时就必须说明为空类型。 如:day

7、ing( ) /*若此句改为“void daying( ) ”,则后面就不能输出值*/ printf(“*n”); main() daying();printf(“%d”,daying( ); 则运行结果为: * 4 /*这里是一个不确定的值*/,(2)有参函数:此类函数在定义及函数说明时都有参数,称为形式参数(简称形参)。在函数调用时也必须给出参数,称为实际参数(简称实参)。 进行函数调用时,主调函数把实参的值传给被调函数的形参,供被调函数使用。 本章节主要讲解用户自定义函数定义、调用等。,6.1.1 函数的定义 自定义函数的形式: 存储类型符 返回值类型符 函数名(形参说明表) 几点说明:

8、 1.存储类型符指的是函数的作用范围,只有两种形式:static和extern。 static说明的函数称为内部函数,只能作用于其所在的源文件, extern说明的函数称为外部函数,可被其他源文件中的函数调用。 缺省情况为extern。,2.返回值类型符指的是函数体语句执行完成后,函数返回值的类型。 如int,float,char等。 若函数无返回值,则用空类型void来定义函数的返回值。 默认情况为int型(有些编译器不支持默认情况)。 3.函数名由任何合法的标识符构成。 建议将函数名的命名与函数内容有一定关系。,4.形参说明表是一系列用逗号分开的形参变量说明。 如:int x, int y

9、, int z 表示形参变量有3个:x, y, z。类型都是int型的。 注意:不能直接写成:int x, y, z。 5.在古典式函数定义中,形参表只要形参名,不要类型名。如:x, y, z 表示形参变量有3个。形参的类型通过形参说明语句说明。如:int x, y, z。 形参说明表或形参表都可以缺省,缺省时表示函数无参数。,6.函数语句体是放在一对花括号 中,由局部数据类型描述和功能实现两部分组成。 函数返回语句 通常用返回语句来结束函数的调用。 两种形式的返回语句: 函数无返回值的情况 return; 函数有返回值的情况 return (表达式的值);,例 无参函数 printstar(

10、 ) printf(“*n”); 或 printstar(void ) printf(“*n”); ,函数的定义的几种不同形式:,函数类型 函数名(形参类型说明表) 说明部分 语句部分 ,现代风格:,例: 有参函数(现代风格) int max(int x, int y) int z; z=xy?x:y; return (z); ,函数类型 函数名(形参表) 形参类型说明 说明部分 语句部分 ,传统风格:,例 :有参函数(传统风格) int max(x,y) int x,y; int z; z=xy?x:y; return (z); ,例如,编写自定义函数abs_sum(),求两个任意整数的绝对

11、值的和。 int abs_sum(int m, int n) if (m0) m=m; if(n0) n=n; return (m+n); 或直接调用系统函数来实现: int abs_sum(int m, int n) return (abs(m)+abs(n); 注意:函数abs()的声明在头文件math.h。,例:定义函数power(x,n), 求x的n次方。,函数定义如下: float power( float x, int n) int i; float t=1; for(i=1;i=n;i+) t = t * x; /* 1*x*x*x 共乘n次 */ return t; /* 返回

12、t的值 */ ,注:一般说来,若定义函数在后,使用在前,则在主调函数中要进行说明后才能调用。若定义函数在前,使用在后,则在主调函数中可不进行说明而直接调用。若函数的返回值是整型,也可不说明而直接使用。,6.1.2 函数的声明和调用 通常情况下,自定义的函数在使用之前要先进行函数声明,才能在程序中进行函数调用。 1函数声明 函数声明语句的形式: 存储类型符 返回值类型符 函数名(形参说明表); 如:int abs_sun(int m, int n); 说明:一般情况下,若函数定义在后,使用在前,则需要对被调用的函数进行声明。(若函数的返回值类型为整型,则声明可以省略。,/* 使用自定义函数,只用

13、一个主函数*/ int max(int,int ,int); /* 对用户定义函数的声明*/ main() int n1,n2,n3,nmax; scanf(“%d%d%d”, ,自定义函数在程序中的使用方式有两种形式: 先进行函数声明,再进行函数 调用,函数定义放在main函数 的后面。 函数定义放在main函数的前面, 再进行函数调用。 (不需要进行函数声明) 例1:编写程序,通过调用函数 int abs_sum(int a,int b), 求任意两个整数的绝对值的和。,#include int abs_sum(int m,int n); /*函数声明*/ main() int x,y,z

14、; scanf(%d%d, ,或者: #include int abs_sum(int m,int n) /*函数定义*/ if(m0) m=-m; if(n0) n=-n; return m+n; main() int x,y,z; scanf(%d%d, ,对被调用函数的声明和函数原型 对被调用函数要求: 必须是已存在的函数(库函数或用户自定义函数) 若是使用库函数,则应在本文件的开头用: #include 命令将调用有关库函数所需用到的信息“包含到该文件中来。否则就无法使用库函数。 若是用户自定义函数,而且主调函数与被调函数在同一个文件中,一般还需在主调函数中对被调函数作声明,即向编译系

15、统声明将要调用此函数。,函数声明 一般形式:函数类型 函数名(形参类型1形参名1,. ); 或:函数类型 函数名();(不提倡使用) 作用:告诉编译系统函数类型、参数个数及类型,以便检验 函数定义与函数声明不同 函数声明位置:程序的数据说明部分(函数内或外) 下列情况下,可不作函数声明 若函数返值是char或int型,系统自动按int型处理 被调用函数定义出现在主调函数之前 在所有的函数定义之前,在函数的外部已做了函数声明 有些系统(如Borland C+)要求函数声明指出函数返回值类型和形参类型,并且对void 和 int 型函数也要进行函数声明,例: 函数声明举例,#include lon

16、g sum(int a, int b); long factorial(int n); main() int n1,n2; long a; scanf(%d,%d, ,long factorial(int n) long rtn=1; int i; for(i=1;i=n;i+) rtn*=i; return(rtn); ,long sum(int a,int b);,long factorial(int n);,函数原型: 在函数声明中不写形参名,只写出形参的类型,这种形式的函数声明称为函数原型。 如:float add(float,float); 使用函数原型是C语言的一个重要特点。 函数

17、原型的一般形式: 函数类型 函数名(形参类型1,形参类型2,. ); 其功能和用法和函数声明一样,2函数调用 函数定义好后,若不通过函数调用,不会发挥任何作用。 函数调用是通过函数调用语句来实现的。 函数无返回值情况: 函数名(实参表); 函数有返回值的情况: 变量名函数名(实参表); 注意:变量名的类型必须与函数的返回值类型相同。 函数调用时,会去执行函数中的语句内容,函数执行完毕后,回到函数的调用处,继续执行程序中函数调用后面的语句。,例如: int x=5, y=10; int z; z=abs_sum(x, y); /*函数调用 */ ,调用方式的几种方式: 函数语句:把函数调用作为单

18、独的一语句,此时不要求函数带回值,只要求函数完成一定的操作。 例:printstar( ); printf(“Hello,World!n”); 注意后面要加一分号才能构成语句,以语句形式调用的函数可以有返回值,也可以没有返回值。 函数表达式:函数调用出现在一个表达式中。此时要求函数必须带回一个确定的值以参加表达式的运算。 例:m=max(a,b)*2; 函数max是表达式的一部分,它的值乘2再赋给变量m。 函数参数:把函数调用作为一个函数的参数。实质上也是函数表达式形式调用的一种,因为参数本来就要求是表达式形式。 例如:printf(“%d”,max(a,b); m=max(a,max(b,c

19、);,6.1.3 函数的传值方式 函数传值的4个要点: 对于带有参数的函数,调用函数时,将实参表中每一个实参的值对应地传递给每一个形参变量; 形参变量接收到实参传来的值后,会在内存临时开辟新的空间,保存形参变量的值; 函数执行完毕时,释放临时开辟的内存空间; 形参的值在函数中不论是否发生变化,实参变量的值均不会发生变化。,形式参数与实际参数 形式参数:定义函数时函数名后面括号中的变量名 实际参数:调用函数时函数名后面括号中的表达式,例 :比较两个数并输出大者,#include main() int a,b,c; int max(int x,int y);/*对被调函数的声明*/ scanf(%

20、d,%d, ,例 : 计算x的立方,#include float cube(float x) return(x*x*x); main() float a, product; printf(Please input value of a:); scanf(%f, ,x,1.2,1.2,1.728,说明: 实参可以是常量、变量或表达式,但必须有确定的值。在调用时将实参的值赋给形参。 在定义函数时形参必须指定类型;在定义函数中指定的形参未出现函数调用时,并不占据内存中的存储单元;只有在发生函数调用时,函数中的形参才被分配内存单元;调用结束后,形参所占的内存单元也同时被释放。 形参与实参应类型一致,个

21、数相同。若形参与实参类型不一致,自动按形参类型转换 (函数调用转换)。 在调用函数时,主调函数与被调函数之间有数据的传递,具体有两种传递方式:单向的值传递与地址传递。,单向的值传递: 将实参的值单向传递给形参的一种参数传递方式。如果形参是普通变量,则是单向的值传递方式,此时形参值的变化不会影响实参的值;函数调用时,为形参分配单元,并将实参的值传递到形参中,形参与实参分别占据不同的内存单元 ;调用结束,形参单元被释放,实参单元仍保留并维持原值。地址传递: 将实参地址传递给形参的一种方式。如果形参是数组名(或指针变量),则传递的是数组的首地址而不是数组的值。此时若形参中的数据发生变化就又可能影响实

22、参中的数据的值。,例: 输入两个数,交换两个数,输出交换前和交换后的两数.,#include main( ) int x=7,y=11; printf(x=%d,y=%dn,x,y); printf(swapped:n); swap(x,y); printf(x=%d,y=%dn,x,y); swap(int a,int b) int temp; temp=a; a=b; b=temp; ,运行结果:x=7, y=11 swapped: x=7, y=11,swap(p1,p2) int *p1,*p2; int p; p=*p1; *p1=*p2; *p2=p; main() int a,b

23、; scanf(%d,%d, ,例: 输入两个数,交换两个数,输出交换前和交换后的两数.,阅读:课本上的例6-1、6-2、6-3,函数的返回值 返回语句 形式: return (表达式); 或 return 表达式; 或 return; 功能:使程序控制从被调用函数返回到主调函数中,同时把返回值带给主调函数 说明: 函数中可有多个return语句 若无return语句,遇 时,自动返回调用函数 若函数类型与return语句中表达式值的类型不一致,按前者为准,自动转换-函数调用转换 void型函数用来明确表明函数不带回任何值,例 :无返回值函数 void swap(int x,int y ) i

24、nt temp; temp=x; x=y; y=temp; ,例: 函数返回值类型自动转换为函数类型,#include main() float a,b; int c; int max(float x,float y); /*函数声明*/ scanf(%f,%f, ,运行结果: 1.5, 4.7 Max is 4,printstar() printf(*); main() int a; a=printstar(); printf(%d,a); ,例: 比较以下两程序的区别。,函数定义时未指定函数类型,默认为整型 输出结果:*10,void printstar() printf(*); main

25、() int a; a=printstar(); printf(%d,a); ,函数定义时明确指定函数无返回值 结果:编译错误!,6.2 变量的作用域和存储类型,1变量的作用域 变量从数据类型角度来分,可分为基本数据类型(整型、实型、字符型和枚举类型)、构造数据类型(数组、结构体、共用体)、指针类型与空类型。 从变量的作用范围(空间角度)来分,又可分为局部变量与全局变量 从变量存在的时间长短(变量的生存期)来分,又可分为动态存储变量与静态存储变量(下节介绍),(1)局部变量 局部变量也称为内部变量 定义:在函数内部或某个控制块的内部定义的变量。只在本函数或某个控制块内有效. 说明: main中

26、定义的变量只在main中有效 不同函数中同名变量,占不同内存单元 例:不同函数中同名变量 形参属于局部变量 可在复合语句中定义变量,这种变量只在此复合语句中有效。 例:复合语句中变量,#include main() int a,b; a=3; b=4; printf(main:a=%d,b=%dn,a,b); sub(); printf(main:a=%d,b=%dn,a,b); sub() int a,b; a=6; b=7; printf(sub:a=%d,b=%dn,a,b); ,运行结果: main:a=3,b=4 sub:a=6,b=7 main:a=3,b=4,运行结果:5 4 3

27、 2 1,/*c7_11.c*/ #include #define N 5 main() int i; int aN=1,2,3,4,5; for(i=0;iN/2;i+) int temp; temp=ai; ai=aN-i-1; aN-i-1=temp; for(i=0;iN;i+) printf(%d ,ai); ,(2) 全局变量 全局变量也称为外部变量 定义:在函数外定义,可为本文件其他函数共用 有效范围:从定义变量的位置开始到本源文件结束。 说明: 设全局变量的作用增加了数据联系的渠道,调用函数一般只能返回一个值,而使用全局变量则能返回多个值(见后面例) 应尽量少使用全局变量,因为

28、: 全局变量在程序全部执行过程中占用存储单元 降低了函数的通用性、可靠性,可移植性 降低程序清晰性,容易出错 若外部变量与局部变量同名,则外部变量被屏蔽,#include int a=3,b=5; max( int a,int b) int c; c=ab?a:b; return(c); main() int a=8; /*局部变量*/ printf(max=%d,max(a,b); ,例: 外部变量与局部变量同名,运行结果:max=8,例:阅读程序【例6-4】的程序, 了解变量作用域。 请注意区分局部变量和全局变量的作用域。,2变量的存储类型 变量的存储类型指的是变量的存储属性,它说明变量占

29、用存储空间的区域。 在内存中,供用户使用的存储区由程序区、静态存储区和动态存储区3部分组成。 变量的存储类型:auto、register、static和extern4种。 auto型变量存储在内存的动态存储区; register型变量保存在寄存器中; static型和extern变量存储在静态存储器。,(1)动态存储方式与静态存储方式 从变量存在的时间(生存期)度角来分变量可分为动态与静态两种存储方式 静态存储:程序运行期间分配固定存储空间 动态存储:程序运行期间根据需要动态分配存储空间 内存用户区 生存期 静态变量: 从程序开始执行到程序结束 动态变量:从包含该变量定义的函数开始执行至函数执

30、行结束 具体包含以下四种: auto-自动型 static-静态型 extern-外部型 register-寄存器型,(1) auto int x; (2) static int y; (3) register int i; (4) int z; extern z;,局部变量的存储类型默认值为auto型。 全局变量的存储类型默认值为extern型。 注意: 一般情况下,常用auto型register型定义局部变量。 static型既可作为局部变量,又可作为全局变量。 作为局部变量时,局部变量的值将被保留,若定义时没有赋初值,则系统会自动为其赋0值; 作为全局变量时,其有效范围为它所在的源文件,

31、其他源文件不能使用。,(2) 自动(auto)局部变量 函数中的局部变量,如不专门声明为static存储类别,都属于动态存储类,存储在动态存储区。这类变量称为自动变量,用关键字(auto)作存储类型的声明 ,也可省略关键字(auto)。 如函数中的形参和在函数体中定义的变量(包括在复合语句中定义的变量)都属此类。,int f (int a) auto int b,c=3; /*形参a ,b、c均为自动存储类别*/,/*等价于int b,c=3;*/,(3)用static声明局部变量 有时希望函数中的局部变量的值在函数调用后不消失而保留原值,则应指定该局部变量为“局部静态变量”,用static加

32、以声明。,说明: 局部静态变量属静态存储类别,在静态存储区内分配存储单元。在程序整个运行期都不释放。 局部静态变量的初值只赋一次。 如果不对静态变量赋初值,则其变量的初值为0; 虽然局部静态变量在函数调用结束后仍然存在,但其它函数是不能引用它的。 什么情况下使用局部静态变量: 需要保留函数上一次调用结束时的值。,如果初始化后,变量只被引用而不必改变其值,用局部静态变量较好。,#include f(int a) auto int b=0; static int c=3; b=b+1; c=c+1; return(a+b+c); main() int a=2,i; for(i=0;i3;i+) p

33、rintf(%d ,f(a); printf(n); ,例:考察静态局部变量的值,运行结果: 7 8 9,例:打印1到5的阶乘(作普通变量表示),#include int fac(int n) int f; if (n=1) f=1; else f=fac(n-1)*n; return(f); main() int i; for(i=1;i=5;i+) printf(%d!=%dn,i,fac(i); ,运行结果: 1! =1 2! =2 3! =6 4! =24 5! =120,例:打印1到5的阶乘 需要保留函数上一次调用结束时的值时用局部静态变量较好。比较下列两程序段:,用普通变量,#in

34、clude int fac(int n) int f=1,i; for (i=1;i=n;i+) f=f*i; return(f); main() int i; for(i=1;i=5;i+) printf(%d!=%dn,i,fac(i); ,使用局部静态变量,#include int fac(int n) static int f=1; f=f*n; return(f); main() int i; for(i=1;i=5;i+) printf(%d!=%dn,i,fac(i); ,(4)register变量 局部变量的值存储在CPU的寄存器中,寄存器比内存操作要快得多,所以常将一些需要反

35、复操作的局部变量放在寄存器中。这类变量称为寄存器变量,用关键字register说明 。 定义格式: register 类型说明 变量名; (其它用法等与auto型变量一样.),说明: 只有局部自动变量和形式参数可作为寄存器变量; 寄存器变量个数有限,若定义了过多的register 变量,则系统会自动将其中的部分改为auto型变量; 局部静态变量不能定义为寄存器变量。 如: register static int a,b,c;是错误的,例:使用寄存器变量,Void main() register int i; int tmp=0; for(i=1;i=100;i+) tmp+=I; printf

36、The sum is %dn,tmp); 这时由于变量i在程序中使用频繁,占用空间小,可以用register变量。,(5) 用static声明外部变量 在定义外部变量时加一个static声明,则这些外部变量只能被本文件使用,而不能被其他文件引用。称为静态外部变量。,例3:设计一个函数:long fac(int n),用来计算正整数的阶乘,编写程序进行测试。 分析:由于计算机对变量的字节长度分配有限,整型变量的最大值是一定的,因此,目前计算整数的阶乘只能针对较小的整数。假定要计算15的阶乘。 算法的核心思想:对于任意正整数n,如果知道(n1)!,则n!=n(n1)!。 可在函数中定义一个stat

37、ic型变量,用来保存每一次阶乘的计算结果。,变量存储类别小结,局部变量默认为auto型 局部static变量具有全局寿命和局部可见性 局部static变量具有可继承性 extern不是变量定义,可扩展外部变量作用域,静态全局变量与静态局部变量的区别,auto型局部变量与静态局部变量的区别,6.3 内部函数与外部函数,自定义的函数有两种:内部函数和外部函数。 1内部函数 若函数的存储类型为static型,则称其为内部函数(内部函数又称为静态函数),它表示在由多个源文件组成的同一个程序中,该函数只能在其所在的文件中使用,在其他文件中不可使用。 内部函数的声明形式: static (); 例如: s

38、tatic int Statistic (); 2外部函数 若函数的存储类型定义为extern型,则称其为外部函数,它表示该函数能被其他源文件调用。 函数的默认存储类型为extern型。,例4:外部函数的应用示例。下面的程序由3个文件组成:file1.c、file2.c、example6_6.c。 在file1.c、file2.c中分别定义了两个外部函数; 在example6_6.c中可以分别调用这两个函数。,1file1.c /* file1.c 外部函数定义 */ extern int add(int m, int n) return (m+n); ,2file2.c /* file2.c

39、 外部函数定义 */ extern int mod(int a, int b) return(a%b); ,3下列程序由三个文件组成:file1file2example66_6.c e #include extern int mod(int a, int b);/*外部函数声明*/ extern int add(int m, int n);/*外部函数声明*/ main() int x, y, result1,result2,result; printf(Please enter x and y:n); scanf (%d%d, ,关于以上程序的几点说明 (1)在程序file1.c、file2

40、.c中的函数定义可以不需要extern加以说明,默认为外部函数。 (2)在example6_6.c中对外部函数的声明也可以不用extern加以说明,默认为外部函数。 (3)由多个源文件组成一个程序时,main()函数只能出现在一个源文件中。 (4)如果将file1.c或file2.c中的extern改成static,则主程序在编译时无法通过。 (5)在程序file1.c或file2.c中,也可以互相调用其外部函数。,由多个源文件组成一个程序时,有3种连接方式: 将各源文件分别编译成目标文件,得到多个目标文件(.obj后缀),然后用连接命令把多个.obj文件连接起来。 Turbo c的连接接命令

41、为tlink 例如:tlink example6_6.obj+file1.obj+file2.obj 结果:生成一个example6_6.exe文件。 建立项目文件(.prj后缀或.dsw后缀),具体操作可参阅各种C语言集成开发环境说明。 使用文件包含命令。(在其后第6节中介绍),如何运行一个多文件的程序,(一)用Turbo C 环境实现多文件程序的运行 先输入并编辑各个源文件分别存盘 建立一个“项目文件” ,只包括组成程序的所有文件名。将此文件以“ *.prj”存盘 在主菜单中选择Project菜单,选择菜单项Project name ,输入刚建立的项目文件名 按+运行。,例如:利用项目管理

42、多个源程序文件,(1)在TC编辑环境下输入以下源程序清单: int a10=0; main() int i; extern getdata(void); getdata(); printf(“i=0;i10;i+) printf(“%4d”,ai); 并以“file1.c”为文件名存盘,(2)在TC编辑环境下输入以下源程序清单: void getdata(void) int i; extern int a10; for(i=0;i10;i+) scanf(“%d”, 并以“file2.c”为文件名存盘,(3)在TC编辑环境下输入以下源程序清单: file1.c file2.c 并以“file.

43、prj”为文件名存盘 (4)在Turboc主菜单中选择“project” “project Name”命令并按回车,在出现的对话框中输入项目文件的文件名“file.prj”后回车 (5)按“Ctrl+F9”即可编译、连接、运行整个程序。,(二)用#include 命令实现多文件程序的运行 格式:#include “源程序文件名” 如果与当前文件不在同文件夹中,还需适当指明路径,如: #include “d:abcf1.c” 此时各文件中的函数被当作在同一文件中,main函数中原有的extern声明可以不要。,例如:用#include 命令实现多文件程序的运行,/*文件f1.c的清单*/ int

44、 max(int a,int b) int z; if(ab) z=a; else z=b; return z; ,/*文件f2.c的清单*/ main() int x1,x2,xmax; scanf(“%d,%d”, ,以上两个程序都不是完整的C源程序,不能单独运行。处理方法如下:,方法一:将文件f2.c的清单改为: #include “f1.c” main() int x1,x2,xmax; scanf(“%d,%d”, 则运行结果为: 3,5 max=5,方法二:新建一源程序文件f3.c,程序清单为: #include “f1.c” #include “f2.c” 编译合并后所得的程序,

45、就能正确运行,6.4 递归函数的设计和调用,函数的嵌套调用: 函数中的语句可以是对另一个函数的调用。 函数嵌套调用的过程如图所示:,嵌套调用属于一种线性调用关系,函数执行完成后,返回到原调用点,继续执行函数调用下面的语句。,6.4 递归函数的设计和调用,函数的递归调用 两种递归形式:直接递归调用和间接递归调用。 直接递归调用 直接递归:函数直接调用自身函数。 间接递归调用 间接递归:函数互相调用对方函数。 递归形式:,6.4 递归函数的设计和调用,可能出现的陷阱 递归调用陷入无限递归状态。 递归的限制 并不是所有的问题都可以设计成递归函数。为了避免错误的发生,对于递归函数的设计,有严格的数学模

46、型。 递归函数的条件 递归函数模型在数学上必须具备以下两个条件。 问题的后一部分与原始问题类似。 问题的后一部分是原始问题的简化。 难点 递归函数设计的难点是建立问题的数学模型,有了正确的递归数学模型,很容易写出递归函数。,6.4 递归函数的设计和调用,例5: 编写程序,要求从键盘输入一个正整数n,计算n!。 分析:n!的数学表达式为: 显然,它满足数学上对递归函数的两个条件: (n1)!与n!是类似的; (n1)!是n!的简化。 可用递归函数long fac(int n)实现求n!。,6.4 递归函数的设计和调用,函数long fac(int n)的算法流程图及函数实现如图所示:,程序: e

47、xample6_7.c,6.4 递归函数的设计和调用,例6:Fibonacci数列的组成规律为:0,1,1,2,3,5,8,13,21,。编写程序,求Fibonacci数列第i项的值(0i40)。 分析:数列的组成规律为:第1项为0,第2项为1,从第3项开始,数列每1项的值为前两项的和。 Fibonacci数列用数字模型表达为: fibonacci(1)=0 (i=1) fibonacci(2)=1 (i=2) fibonacci(i)=fibonacci(i1)+fibonacci(i2) (i=3,4,5,) 从第3项开始,该Fibonacci数列的数学表达式满足递归函数的两个必要条件,设

48、计递归函数long fibonacci (int n)来求得数列中第n项的值。,6.4 递归函数的设计和调用,函数long fibonacci (int n)的算法流程图:,思考程序存在的缺陷: 只能求出指定项的值; 对输入的值没有限制; ,函数程序: long fibonacci(int n) if(n=1|n=2) return n-1; else return fibonacci(n-1)+fibonacci(n-2); ,程序: example6_8.c,6.5 预 处 理,预处理的作用: 向编译系统发布信息或命令,告诉编译系统在对源程序进行编译之前应做些什么事。 所有编译预处理都是以

49、“#”号开头,单占源程序中的一行,放在源程序的首部。 编译预处理不是C语句,行未不必加分号。 C语言提供的预处理指令主要有3种: 宏定义、文件包含和条件编译。,6.5 预 处 理,6.5.1 宏定义 两种宏定义:不带参数的宏和带参数的宏。 宏定义的作用:简化程序的书写。 1不带参数的宏 定义形式: # define 宏名 字符串 说明: define是关键字,表示宏定义。 宏名用标识符表示,为区别于变量,宏名一般采用大写字母。 如:# define PI 3.14159 宏的作用:将程序中的宏名用字符串替换。 宏名的有效范围是从定义命令之后,直到源程序文件结束,或遇到宏定义终止命令#undef

50、为止。 例7:阅读程序example6_9.c,了解不带参数的宏的作用。,6.5 预 处 理,2带参数的宏 定义形式: #define 宏名(参数表) 字符串 说明: 字符串应包含有参数表中的参数。 宏替换时,将字符串中的参数用实参表中的实参替换。 例8:阅读程序example6_10.c,了解带参数的宏定义的作用。分析程序运行结果。 特别提示: 有参数的宏定义与函数是完全不同的两个概念。,6.5 预 处 理,6.5.2 文件包含 将另一个文件的全部内容包含到程序中,编译时,用包含文件的内容取代该预处理命令。 文件包含命令的一般形式: #include 或: #include 包含文件名 注意

51、: include是命令关键字,一个include命令只能包含一个文件。 表示被包含文件在标准目录(include)中。 表示被包含文件在指定的目录中,若只有文件名不带路径,则在当前目录中,若找不到,再到标准目录中寻找。 包含文件名可以是.c源文件或.h头文件,如: # include # include myhead.h # include D:myexammyfile.c”,6.5 预 处 理,文件包含的作用: 将多个源文件拼接在一起。 如:有文件file2.c,其内容都是自定义的函数。 另有文件file1.c,该文件有main函数。 如果在file1.c程序中要调用file2.c中的函数

52、,可采用文件包含的形式:#include file2.c 在对file1.c进行编译时,系统会用file2.c的内容替换掉文件包含命令#include file2.c,然后再对其进行编译。 要注意区分外部函数与文件包含的区别。 它们都是可以在某个程序中用到另一个文件中的函数,但使用的方法有所不同。,6.5 预 处 理,6.5.3 条件编译及其他 条件编译:对程序源代码有选择地进行编译。 ANSI标准定义的C语言预处理命令: #error #if #else #elif #endif #ifdef #ifndef #line #pragma,条件编译命令,略,6.6 综 合 范 例,例7:编写程序,用扩展ASCII中的制表符在屏幕上画一

温馨提示

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

评论

0/150

提交评论