第7章 函数及预处理_第1页
第7章 函数及预处理_第2页
第7章 函数及预处理_第3页
第7章 函数及预处理_第4页
第7章 函数及预处理_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

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

文档简介

1、 第7章 函数与预处理主要内容主要内容 7.1 概述概述 7.2 定义函数的一般形式定义函数的一般形式 7.3 函数参数和函数的值函数参数和函数的值 7.4 函数的调用函数的调用 *7.5 内置函数内置函数 *7.6 函数的重载函数的重载 *7.7 函数模板函数模板 *7.8 有默认参数的函数有默认参数的函数 7.11 局部变量和全局变量局部变量和全局变量 7.14 关于变量的声明和定义关于变量的声明和定义 7.16 预处理命令预处理命令7.1 概述概述 程序结构清晰,可读性好。 减少重复编码的工作量。 可多人共同编制一个大程序,缩短程序设计周期,提高程序设计和调试的效率。C+程序程序源程序文

2、件源程序文件n函数函数1函数函数m 源程序文件源程序文件1函数函数1函数函数n图7.是一个程序中函数调用的示意图。图7.#include using namespace std;void printstar(void) /定义printstar函数 cout* endl; /输出30个“*”void print_message(void) /定义print_message函数 cout Welcome to C+!endl; /输出一行文字int main(void)printstar( ); /调用printstar 函数 print_message( ); /调用print_message

3、函数printstar( ); /调用printstar 函数return 0;例7.1 在主函数中调用其他函数 从用户使用的角度看,函数有两种: 系统函数,即库函数。这是由编译系统提供的,用户不必自己定义这些函数,可以直接使用它们。用户自己定义的函数。用以解决用户的专门需要。 从函数的形式看,函数分两类:无参函数。调用函数时不必给出参数。有参函数。在调用函数时,要给出参数。在主调函数和被调用函数之间有数据传递。函数的分类函数的分类即函数返回值的类型。无返回值为void类型语句序列。描述了实现功能的过程,并一般要最后执行一条return语句。可包含多个形式参数。定义了函数将从调用函数中接收多少

4、个数据及其类型7.3.1 形式参数和实际参数在调用函数时,大多数情况下,函数是带参数的。主调函数和被调用函数之间有数据传递关系,数据传递的方向是从实参传向形参。形参:在定义函数时函数名后面括号中的变量名称为形式参数(formal parameter,简称形参)实参:在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为实际参数(actual parameter,简称实参)。7.3 函数参数和函数的值函数参数和函数的值例例7.2 调用函数时的数据传递调用函数时的数据传递#include using namespace std;int max(int x,int y) /定义有

5、参函数maxint z; z=xy?x:y;return(z);int main( )int a,b,c; coutab; c=max(a,b); /调用max函数,给定实参为a,b。函数值赋给c coutmax=cendl;return 0;运行情况如下:please enter two integer numbers:2 3max=3图7.2有关形参与实参的说明:(1) 在定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,只有在发生函数调用时,函数max中的形参才被分配内存单元,以便接收从实参传来的数据。在调用结束后,形参所占的内存单元也被释放。(2) 实参可以是常量、

6、变量或表达式,如max(3, a+b);但要求a和b有确定的值。 (3) 在定义函数时,必须在函数首部指定形参的类型;(4) 实参与形参的类型应相同或赋值兼容。如果实参与形参类型不同,则按不同类型数值的赋值规则进行转换。(5) 实参变量对形参变量的数据传递是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回来给实参。在调用函数时,编译系统临时给形参分配存储单元。请注意: 实参单元与形参单元是不同的单元。图7.3表示将实参和的值2和3传递给对应的形参和。图7.3 图7.47.3.2函数的返回值函数的返回值说明:(1) 函数的返回值是通过函数中的return语句获得的。return语句将被

7、调用函数中的一个确定值带回主调函数中去。return语句后面的括号可以要,也可以不要。(2) 函数值的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。(3) 如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准,即函数类型决定返回值的类型。对数值型数据,可以自动进行类型转换。7.4.1 函数调用的一般形式 函数名(实参表列)7.4.2 函数调用的方式按函数在语句中的作用来分,可以有以下3种函数调用方式:. 函数语句把函数调用单独作为一个语句,并不要求函数带回一个值,只是要求函数完成一定的操作。如例7.1中的printstar( );

8、2. 函数表达式函数出现在一个表达式中,这时要求函数带回一个确定的值以参加表达式的运算。如c=2*max(a,b);3. 函数参数函数调用作为一个函数的实参。如m=max(a,max(b,c); /max(b,c)是函数调用,其值作为外层max函数调用的一个实参7.4 函数的调用函数的调用函数声明函数声明调用表达式调用表达式函数定义函数定义实参的个数、类型及顺序要与形参保持一致形式参数实际参数即所有参数的数据类型注注 意意#include /函数说明void f1 ( ) ;void f2 ( ) ;void main( ) f1( ); /函数调用void f1( ) /函数定义 cout

9、Function f1.n;f2( );void f2( ) cout y) ? x: y); double max (double x , double y) return ( (xy) ?x: y); #include void main( ) coutmax(10,20)endl; coutmax(1.23,2.34)endl; 将实参的个数及类型和所被调用的f()函数的形参的个数及类型一一比较来判断。()作为重载函数至少在参数个数、参数类型上有所不同。若仅在返回类型上不同,编译器是无法区别的。如:void func(int); int func(int);void func(int);

10、 int func(int); /错误 int min(int ,int); int min(int ,int); int min(int,int,int);int min(int,int,int); /正确 int add(int,int); int add(int,int); double add(double,double);double add(double,double);/正确()typedef定义的类型只是给已有类型取另外一个名字,编译器不能将其同原类型区分。如: typedef INT int;typedef INT int; void func(int x) . void f

11、unc(int x) . void func (INT x) void func (INT x) (3)重载函数一般应具有相同的功能,否则会破坏程序的可读性。7.7函数模板函数模板 所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。 在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。#include using namespace std;template T max(T a,T b,T c) if(ba) a=b; if(ca) a=c; return a;int main( )int

12、i1=185,i2=-76,i3=567,i; double d1=56.87,d2=90.23,d3=-3217.78,d; long g1=67854,g2=-912456, g3=673456,g;i=max(i1,i2,i3); d=max(d1,d2,d3); g=max(g1,g2,g3); couti_max=iendl; coutf_max=fendl; coutg_max=gendl; return 0;template 由于使用不同求值顺序的编译器而造成二义性。 #include #include int add(int x, int y); int add(int x,

13、int y); /函数声明函数声明 void main( )void main( ) int a=4,b=6; int a=4,b=6; int z=add( int z=add(+a,a+b+a,a+b); /); /从左至右为从左至右为5 115 11 coutzendl; / coutzendl; /从右至左为从右至左为5 105 10 int add(int x,int y) int add(int x,int y) /函数定义(实现)函数定义(实现) return x+y; return x+y; 如果函数的定义在函数调用之前,则应在函数定义中给出默认值。如果函数的定义在函数调用之后

14、,则在函数调用之前需要有函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给出默认值.#include using namespace std;int main( )int max(int a, int b, int c=0);int a,b,c; cinabc; coutmax(a,b,c)=max(a,b,c)endl; coutmax(a,b)=max(a,b)a) a=b; if(ca) a=c; return a;一个函数不能既作为重载函数,又作为一个函数不能既作为重载函数,又作为有默认参数的函数。有默认参数的函数。#include using namespace std;

15、int main( )int max(int a,int b,int c=100); int max(int a,int b); int a=8,b=-12,c=27; coutmax(a,b,c)=max(a,b,c)endl; coutmax(a,b)=max(a,b)a) a=b;if(ca) a=c; return a;int max(int a,int b) if(ab) return a;else return b; 在一个函数内部定义的变量,只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的。 同样,在复合语句中定义的变量只在本复合语句范围

16、内有效。 这类变量称为局部变量局部变量(local variable)。7.11 局部变量和全局变量局部变量和全局变量 1 、局部变量、局部变量2、全局变量、全局变量 在函数之外定义的变量是外部变量,称为全局变全局变量量(global variable,也称全程变量)。 全局变量的有效范围为从定义变量的位置开始到本源文件结束。例例#include using namespace std; double Pi=3.14; int main( ) float s=0,r=7.5; s=Pi*fun(r); int l=0;l=2*Pi*r;coutl; couts; return 0; doubl

17、e fun(float x)int y=0;y=x*x;return y;局部变量说明(1) 主函数main中定义的变量也只在主函数中有效,不会因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。(2) 不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰。它们在内存中占不同的单元,不会混淆。(3) 可以在一个函数内的复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为分程序或程序块。(4) 形式参数也是局部变量,其他函数不能调用。(5) 在函数声明中出现的参数名,其作用范围只在本行的括号内。实际上,编译系统对函数声明中的变量名是忽略的,即使

18、在调用函数时也没有为它们分配存储单元。例如int max(int a,int b); /函数声明中出现a、b int max(int x,int y) /函数定义,形参是x、y coutxyendl; /合法,x、y在函数体中有效 coutabendl; /非法,a、b在函数体中无效编译时认为max函数体中的a和b未经定义。全局变量说明 (1) 设全局变量的作用是增加函数间数据联系的渠道。(2) 建议不在必要时不要使用全局变量,因为: 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。 它使函数的通用性降低了,因为在执行函数时要受到外部变量的影响。 使用全局变量过多,会

19、降低程序的清晰性。在各个函数执行时都可能改变全局变量的值,程序容易出错。 因此,要限制使用全局变量。(3) 如果在同一个源文件中,全局变量与局部变量同名,则在局部变量的作用范围内,全局变量被屏蔽,即它不起作用。变量的有效范围称为变量的作用域(scope)。归纳起来,变量有4种不同的作用域、文件作用域(file scope)、函数作用域(function scope)、块作用域(block scope)和函数原型作用域(function prototype scope)。文件作用域是全局的,其他三者是局部的。除了变量之外,任何以标识符代表的实体都有作用域,概念与变量的作用域相似。#include

20、using namespace std;int main()static int m;extern int n;cout m (Y)?(X):(Y)7.16 编译预处理(续)编译预处理(续)7.16 编译预处理(续)编译预处理(续)【例】带参数的宏定义。#define MAX(x,y) (x)(y)?(x):(y)main( ) coutMAX(a,b); cout MAX(a+m,b+n);分两次替换:分两次替换:将宏名将宏名 替换成字符串替换成字符串 。用实参用实参a替换形参替换形参x,实参,实参b替换形参替换形参y。程序中的两个程序中的两个printf语句被展开为:语句被展开为:cout

21、(b)?(a):(b); cout(b+n)?( a+m):( b+n);7.16 编译预处理(续)编译预处理(续)【例】分析下面程序运行后的输出结果。#define MA(x) x*(x-1)main( ) int a=1,b=2; cout MA(1+a+b);分两次替换:分两次替换: 用用 替换。替换。用用1+a+b替换替换x。cout语句被展开为:语句被展开为:cout (1+a+b*(1+a+b-1);特别注意:特别注意:由于替换文由于替换文本中的本中的x没没有用括号括有用括号括起,因此,起,因此,1+a+b也不也不能用括号括能用括号括起。起。程序输出结果:87.16 编译预处理(续)编译预处理(续)命令的一般形式格式1: #include 格式2: #include 文件名7.16编译预处理(续)编译预处理(续)例如:调用sin(x) 函数时,要在程序的开头使用如下命令: #include 在预处理时,用cmath文件内容替换 #include 命令行。7.

温馨提示

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

最新文档

评论

0/150

提交评论