1 / 41

第 5 章 函数与数据控制

第 5 章 函数与数据控制. 学习目的: ① 掌握函数的定义与使用方法; ② 深入理解参数转递及变量作用域; ③ 了解函数的顺序控制机制; ④ 掌握函数指针概念及数组做函数参数。. 5.1 函数定义与说明 5.2 数据控制 5.3 函数的顺序控制 5.4 相关的其他语法 5.5 常用系统函数. 5.1 函数定义与说明. 函数在程序设计中用来描述相对独立的功能,其中包含实现所述功能的一系列具体操作步骤。更复杂的功能通过调用一系列相对简单的函数来完成,这些简单函数的功能更加单一,结构更加简单易读。

ianna
Download Presentation

第 5 章 函数与数据控制

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第5章 函数与数据控制 学习目的: ① 掌握函数的定义与使用方法; ② 深入理解参数转递及变量作用域; ③ 了解函数的顺序控制机制; ④ 掌握函数指针概念及数组做函数参数。 5.1函数定义与说明 5.2数据控制 5.3函数的顺序控制 5.4相关的其他语法 5.5常用系统函数

  2. 5.1 函数定义与说明 函数在程序设计中用来描述相对独立的功能,其中包含实现所述功能的一系列具体操作步骤。更复杂的功能通过调用一系列相对简单的函数来完成,这些简单函数的功能更加单一,结构更加简单易读。 使用函数的意义还在于,通过将函数头作为函数内部实现与外部调用环境之间的接口,实现了数据与程序代码的封装,隐藏了程序实现的细节问题,具有十分明显的模块化、参数化和结构化特征。 函数的定义及使用包括三个方面的内容:函数定义、说明及调用。 5.1.1 函数定义 5.1.2 函数说明 5.1.3 函数的简单调用 5.1.4 函数的重载

  3. 函数 函数头 函数体 函数头 参数表 返回值类型 函数名 函数体 语句 参数表 参数名 类型 空格 ; ) ( } { 5.1.1 函数定义 函数由函数头、函数体两个部分组成,规则如下: 下面为函数定义示例,该函数的功能是返回两个浮点数的积: double GetProduct(double x, double y) { double temp=x*y; return temp; }

  4. 5.1.2 函数说明 函数在使用前必须进行定义,如果函数的调用不是位于同一个文件中函数定义之后,则必须在调用函数之前对函数进行引用说明。通常的做法是使用 #include 指令将含有函数引用说明的文件嵌入进来。 1 函数原型 C++中函数原型给出函数引用说明,任何函数都有自己的函数原型,它可能由编译器从一个函数定义中自动抽取,也可由程序员在程序中通过函数说明语句给出。 函数原型的真正价值是使编译器能够按照所声明的形式进行类型检查,从而发现函数调用中可能存在的错误。 形式上函数原型与函数头相似,但参数表中的参数名可与函数定义中对应位置的参数名不同,也可省略,但类型必须相同。例如: void Swap(int* pX, int* pY); 与下述形式代表的是同一个函数原型 void Swap(int*, int*);

  5. 5.1.2 函数说明 在函数说明中可以为函数的参数指定默认值。调用函数时如果没显式地指定参数的值,编译器就会使用相应的默认值,例如: int Increase(int i=0); //调用时可写为 Increase() ,意指Increase(0) 对参数指定默认值必须从参数表最右边的参数开始连续指定,不允许跨越一个参数而指定其左侧参数的默认值,例如下述函数原型非法: void MoveToPosition(int x=0, int y, int z=0); void MoveToPosition(int x=0, int y=0, int z); 而下述函数原型合法: void MoveToPosition(int x, int y=0, int z=0); 函数调用时,编译器将按从左至右的顺序将实参与形参结合,当实参数目少于形参数目时,将按顺序用默认值补足所缺少的实参,例如对于上面的函数说明,下面两种方式等价: MoveToPosition(3, 8); MoveToPostion(3, 8, 0); 2 函数参数默认值

  6. 5.1.2 函数说明 函数内操作完成后,使用返回语句将某值传递给调用函数,格式为: return <exp>; 程序运行至该语句时,计算<exp>的值并传递给调用函数,然后将程序执行的控制权移交给调用函数,执行紧跟当前函数调用语句后的语句。 3 函数的返回值 [例5.1] 编写函数比较两个浮点数的大小,要求:当第一个浮点数比第 二个大时返回1;相等时返回0;否则返回-1。 int FloatCmp(float f1, float f2) { float f=f1-f2; if(fabs(f)<0.0001) return 0; else if(f<-0.0001) return -1; else return 1; }

  7. 5.1.3 函数的简单调用 函数的使用方式很灵活,可以用作某个运算的操作数,也可以作为单独的一条语句出现在程序中,实际上作为一种表达式,函数调用几乎可以出现在程序中任何表达式能够出现的地方。 在具体调用函数时,应该根据函数原型中对参数类型的要求用相应的实际数据替换函数的参数,例如下列程序段: #include "math.h" #include "iostream.h“ int GetMinimum(int m, int n) { return m>n ? n : m; } void main() { cout<<sqrt(36+GetMinimum(64, 81))<<endl; }

  8. 5.1.4 函数的重载 具有相同名字、参数类型或参数个数有所不同的函数称为重载函数。 C++中规定,重载函数的形式参数在类型或个数上必须有所区别,因此在定义重载函数时应注意这些函数的原型是不同的。例如: //参数类型不同的重载函数 int GetSum(int x, int y) {…} float GetSum(float x, float y) {…} //与上面函数同名,参数类型不同 //参数个数不同的重载函数 float GetSum(int x, int y, float z) {…} //上面函数同名,参数个数不同 //错误的重载函数 int GetSum(float x, float y) {…} //非法,与第一个函数比仅返回值类型不同

  9. 5.1.4 函数的重载 #include "iostream.h" int GetMax(int x, int y) {return x>y ? x:y;} //第一个函数 double GetMax(double x, int y) {return x>y ? x:y;} //第二个函数 double GetMax(double x) {return x;}//第三个函数 void main() { cout<<"The maxmium is "<<GetMax(3.6, 3)<<endl; //调用第二个函数 cout<<"The maxmium is "<<GetMax(4, 8)<<endl; //调用第一个函数 cout<<"The maxmium is "<<GetMax(7)<<endl; //调用第三个函数 } [例5.3] 通过函数求两个数据中的最大值

  10. 5.2 数据控制 高级语言的数据控制机制决定了标识符与变量、函数定义等的映射关系,决定了操作结果如何存储、以及如何查询这些结果用于后续操作。由于数据对象的使用方式具有多样性,因此数据控制的含义很广,涉及函数参数的传递机制以及函数间数据信息传递、变量的作用域等重要概念。 5.2.1 参数传递机制 5.2.2 数据对象的引用* 5.2.3 作用域

  11. 5.2.1 参数传递机制 函数定义中的参数并没有被具体赋值,该参数代表将来使用函数时的任何一个数据对象,所以该参数不具有真实的确定值,因此称为形式参数,简称形参。 形式参数 实在参数 如同使用数学中的函数进行数学运算,程序中调用函数时要为函数的形参指定具体的数据对象或取值,它们称为实在参数,简称实参。 实参用于调用函数时给函数的形式参数赋初值。 由于作为实参的数据对象具有名字、值、地址等属性,因此必须对实参与形参之间如何对应(结合)做出规定。通常有三类接合方式: 传值调用 传址调用 引用调用

  12. 5.2.1 参数传递机制 形式参数被赋予实在参数的(右)值,而在函数体中形式参数等价于在函数内定义的局部变量。由于形参仅仅被赋予了实参的右值,因此被调函数形参的任何变化都不会引起定义于调用函数中的实参的改变。 1 传值调用 [例5.4] 传值调用示例 #include "iostream.h" int func(int a) { cout<<"The formal parameter is "<<a<<endl; a=8; return a; } void main(int argc, char* argv[]) { int* pa=new int; *pa=5; func(*pa); cout<<"The real parameter is "<<*pa<<endl; // *pa并未改变 }

  13. 5.2.1 参数传递机制 形式参数和实在参数代表内存中同一个数据对象,形实结合时,形式参数被赋予实在参数的左值,因此形式参数的变化就是实在参数的变化。 2 传址调用 [例5.6] 传址调用示例 #include "iostream.h" int func(int a[]) { a[2]=8; return 0; } void main(int argc, char* argv[]) { int a[]={1,2,3,4,5}; func(a); cout<<a[2]<<endl; }

  14. 5.2.1 参数传递机制 引用调用将作为实参的表达式的左值传递给被调函数,实现时相当于以实在为初值,定义一引用类型变量(实参的别名),形参和实参为同一数据对象的标识。 使用引用调用和传址调用可以实现相同的功能,但引用调用的使用方式更方便、直观,其使用方法示例如下: 3 引用调用 [例5.8] 引用调用示例 #include "iostream.h" void Swap(int& p, int& q) { int temp=p; p=q; q=temp; cout<<"p="<<p<<", q="<<q<<endl; } void main() { int x=2, y=3; Swap(x, y); cout<<"x="<<x<<", y="<<y<<endl; }

  15. 5.2.2 数据对象的引用* 函数可以被反复多次调用,并且可以嵌套调用,另外函数的不同部分可能出现相同的标识符,如何确定标识符与具体数据对象之间的联系、如何引用数据对象,是数据控制的重要内容,与函数有密切关系。 1 引用方式 常用引用方式有三种: 直接传递、通过对象名引用、通过指针名引用。 直接传递 数据对象作为中间计算结果直接传给另一操作,例如x=y+2*z中,2*z的操作结果被存于一隐藏的临时变量中,并直接传递给语句x=y+2*z参加运算。 通过对象名引用数据对象名字出现在表达式中表示对相关数据对象的引用,例如x=y+2,y的表示相应的数据对象参与加法操作,即通过对象名字引用数据对象。 通过指针名引用可通过指向匿名对象的指针引用该对象,例如: char* pC=new char[20]; *(pC+1)=‘f’; 动态定义数据对象时未指定对象名字,pC本身是一个数据对象,被赋值后指向所创建的匿名数据对象,因而可以通过pC引用所指向的匿名数据对象。

  16. 5.2.2 数据对象的引用* 程序设计语言提供给编程者的数据对象引用方式为通过标识符引用,但是由于函数可以被多次调用,因此通过函数中的标识符得到与它们所代表的数据对象的值是一个十分复杂的过程,一般经过三个步骤。 2 实现步骤 标识符到声明 出现于不同程序段的同一名字所代表的数据对象可可能相同,也可能不同,确定标识符代表的数据对象首先要判断它与哪个声明语句相关联,因为任何数据对象都由声明创建。因为任何标识符都出现在相应的数据对象声明作用域内,因此该关联由作用域规则决定。 从声明到存储地址 标识符代表某数据对象声明所创建的数据对象,实际情形更复杂:函数可不只一次被调用,甚至嵌套。尽管创建的时机不同,内存中可能同时存在由同一说明语句创建的多个数据对象,哪个数据对象与函数当前活动相联系,需在调用时将标识符约束到某确定存储地址。相关信息被记录在当前活动记录中。 从存储地址到值 得到存储地址也就是定位了数据对象,下一步需要判断标识符的引用究竟是代表数据对象的左值还是数据对象的右值。

  17. 5.2.2 数据对象的引用* 由于引用,需要为各种标识符建立与数据对象之间的对应关系,即绑定(映射、关联),程序运行过程中将通过这种关联引用数据对象。 对于程序或函数总有一组关联,用于在执行期间指明该阶段将遇到的所用标识符与数据对象的对应,这组关联称为函数的引用环境,由下面几个部分组成: 3 引用环境 局部引用环境一组表示形参、函数内部局部变量及调用函数的关联,每当进入该函数时重新创建一次;从函数退出时删除。利用局部引用环境可确定函数本次调用期间各局部变量和所调用函数的引用含义。 非局部引用环境 并未在函数被调用初始时刻生成,但是在进入函数后仍可以使用的标识符的关联的集合。 全局引用环境在主程序开始运行前就创建的一组关联,如果这些关联在函数中可以被引用,则这些关联构成了函数的全局引用环境。 预定义引用环境在语言定义时就已经定义的关联,它们同样可以在函数中引用,但无必要再次创建这类标识符的关联,如cout、cin等。

  18. 5.2.2 数据对象的引用* 4 可见性 程序中的每个标识符都会在适当时段与数据对象间建立起确定的关联,如果某个关联是一个函数引用环境的一部分,那么这个关联中的标识符作为与之相联的数据对象的标识可以在该函数中被引用,我们称之为在该函数中可见。如果某标识符的关联存在但不是某函数引用环境的一部分,则称该关联对这个函数是隐藏的。可见的标识符可以在函数中访问,而不可见的标识符不能访问。

  19. 5.2.3 作用域 无论标识符标识的是变量、常量、语句标号、函数,都有一定的有效范围,超出这个范围标识符就失去效用,该范围称为标识符的作用域。 静态作用域 静态作用域 标识符在程序段中的作用域(指程序的部分文本)。 静态作用域规则:确定一个标识符静态作用域的规定。 高级语言编译器通过静态作用域规则确定标识符说明的静态作用域,从而将程序文本中的名字的引用同它的声明联系起来。 静态作用域的概念和规则有助于提高程序运行效率。 动态作用域 用环境的一部分,在程序运行期间将标识符与数据对象的引用联系在一起,即,名字的使用与其所代表的数据对象之间的绑定是动态建立的,随着程序的运行可以发生变化。多数语言采用静态作用域规则。

  20. 5.2.3 作用域 标识符只能在其说明或定义的范围内可见,在此范围外不可见。 1 C++的作用域规则 作用域分为如下4类: 程序级作用域范围包括组成程序的所有文件,可在所有文件中引用该 类标识符。具有该作用域的标识符常为外部函数和外部变量,它们都在某文件中定义,在其他文件中进行引用说明,此时标 识符作用域从引用说明语句或定义语句开始到文件尾。 文件级 该类标识符只能被所定义文件访问,作用域从说明语句开始到文件结尾。具有该类作用域的有内部函数和外部静态变量。 函数级 函数内从说明语句位置开始直到该函数结束。函数内部定义的自动变量、内部静态变量及语句标号等具有函数级作用域。 块 级 从标识符定义处开始到分程序(块)结尾,即 { } 之间,从标识符定义处开始到 } 为止。

  21. 5.2.3 作用域 具有程序级或者文件级的变量,包含外部变量(external variable)和外部静态变量(external static variable)。 外部变量在所有函数体、类之外定义,作用域为:在定义该变量的文件中,从变量定义处开始到文件结束;在其他文件中,从外部变量引用声明开始到文件结尾。 2 全局变量 [例5.9] 外部变量定义及其引用示例 文件test.cpp的内容: #include "iostream.h" extern int global; // 引用声明 void func1(void) //外部变量引用 { cout<<global<<" is from the variable defined in other file"<<endl; } void main(int argc, char* argv[]) { func1(); } 文件test1.cpp的内容: int global(10); //外部变量定义 int func2() { return global+2; }

  22. 5.2.3 作用域 [例5.10] 静态外部变量的定义及引用示例。 2 全局变量 #include "iostream.h" static int nTotal=0; void Add1(void) { nTotal++; } void Add2(void) { nTotal+=2; } void main(int argc, char* argv[]) { Add1(); Add2(); cout<<"Total is "<<nTotal<<endl; }

  23. 5.2.3 作用域 内部变量(internal variable)或局部变量(local variable)包括函数级变量和块级变量。函数级变量指函数的形式参数和函数体中定义的变量;块级变量指分程序两个匹配花括号 { } 之间定义的变量。函数形参的作用域为整个函数,而函数内部定义变量和分程序中定义的变量,其作用域从定义处开始到函数结尾或分程序结尾。 执行程序时,每次进入局部变量的作用域(包括自嵌套时的每次重复进入),都会为其间的所有局部变量分配存储空间,每次从函数或分程序退出后,这些局部变量变为无效,程序将自动释放局部变量所占用的存储空间,因此局部变量又常称为局部自动变量,在声明这类变量时可以使用关键字auto,也可以省略。 3 局部变量

  24. int x; • void MyFunction() • … A B { … int x; … for(…) … } { int x; … } C 5.2.3 作用域 [例5.11] 局部变量定义及引用示例 int x; // x是全局变量 void MyFunction() { auto int y;// 局部变量; auto可以省略 int x;// 局部变量x隐藏了全局变量x x=1; for(int i=0; i<=2; i++) { int x;// 此处的局部变量x又隐藏前一局部变量 x=2; // 对此处的局部变量x赋值 static int nStatic=8; // 此处定义局部静态变量 nStatic++; } x=3; // 对第一个局部变量x赋值 ::x=9; // 对全局变量x赋值 } int z=x; // 引用全局变量x 3 局部变量

  25. 5.2.3 作用域 内部函数是只能在其定义所在文件中引用的函数,常称为静态函数。 静态函数的优点是在其他文件中不可见,有一些不希望其他文件引用的函数,比如可能以后进行大改动的函数,可以声明为静态函数。 静态函数的定义在形式上仅仅是在一般函数的定义前加一个关键字static即可,如下例所示: 4 外部函数与内部函数 #include "iostream.h" static int GetASCII(char c) { return c; } void main() { cout<<GetASCII('a')<<endl; } 外部函数是可在其定义文件之外访问的函数,在非定义文件中对外部函数访问前必须进行外部引用声明 。(使用VC++调试 例5.12)。

  26. 开辟新的运行环境 保存现场 参数结合 执行分程序 恢复现场 释放本函数的运行环境 返回 5.3 函数的顺序控制 函数的顺序控制是高级语言中操作顺序控制的重要组成部分,涉及到函数调用机制、数据传递机制的实现等方面的内容。 调用函数调用被调函数的操作过程是暂时中断当前函数的执行,将CPU使用和控制权移交给被调函数;从被调函数退出后,再将CPU控制权还给调用函数;为使调用函数能够在原来暂时中断的地方继续运行,执行被调函数前,将调用函数中所有保证程序正常运行的信息保存下来,这些信息包括调用函数 5.3.1 函数执行模型* 5.3.2 基于栈的实现* 5.3.3 函数的自嵌套调用 内部作用域内中所有变量的存储区(用于存储形式参数、局部变量、临时变量)、调用函数的返回地址存储单元(保存调用函数返回后将执行的第一个指令地址及其所在函数的环境地址)、调用函数返回值存储单元地址等,它们一起构成了函数的运行环境。

  27. 5.3.1 函数执行模型* 当前指令指针 CIP:程序运行时,任何时刻都有某个指令被执行或将被 执行,这个指令被称为当前指令,它在内存中的位 置保存在一个被称为当前指令指针。 当前环境指针 CEP:活动记录由函数的局部数据、参数、以及有关的其 它数据项记录组成。 C++编译器将为主程序生成一个活动记录,该活动记录与程序的其他代码一起在执行程序时调入内存,同时将CEP指向该活动记录,CIP指向程序代码段的第一条指令。 每次调用函数时都创建一个新的活动记录,将CEP指向该活动记录,将CIP指向函数第一条指令,于是程序将顺序执行该函数。函数调用其他函数时,将重复这个过程,创建相应的活动记录并给CEP和CIP赋值。 为从函数正确返回,对CEP和CIP赋新值前必须将它们的值保存在新调用函数活动记录中,CIP的值保存为紧跟在该函数调用语句之后的指令地址,从函数中退出时,从被调函数活动记录中取得先前保存的值,然后对CEP和CIP重新赋值,从而程序将继续执行调用函数中的剩余语句。

  28. 主程序 函数A 函数B … … … … A的调用指令 instruction1 … … … … B的调用指令 instruction2 … … … … A的调用指令 instruction3 … … … … … … … … B的调用指令 instruction4 … … … … 返 回 instruction5 … … … … 返 回 静态代码段 常 量 常 量 常 量 record1 返回点 record2 record3 … … … … … … … … instruction1 record1 instruction4 record2 活动记录 局部变量 局部变量 局部变量 CIP instruction5 CEP record3 5.3.1 函数执行模型* #include "iostream.h" int B(int b1, int b2) { int x=b1+=b2; return x; } void A(int a) { a+=B(4,5); } void main() { A(3); B(6,7); A(2); }

  29. 数据对象,这些局部数据对象被放置在函数的本次调用活动记录中。数据对象,这些局部数据对象被放置在函数的本次调用活动记录中。 5.3.2 基于栈的实现* C++与C语言采用栈实现上述运行模型,每个处于运行状态的程序都有一个动态变化的栈和内容不变、静态分配的代码段。栈用于保存调用函数时创建的被调函数活动记录,其中存有调用函数的CEP和CIP及被调函数的形式参数、局部变量等局部数据对象。因此重复运行函数相当于运行相同的函数代码,但函数体中的操作数(标识符)每次调用对应于不同的数据对象,这些局部数据对象被放置在函数的本次调用活动记录中。

  30. 5.3.3 函数的自嵌套调用 C++函数调用机制的实现允许一个函数在其内部调用它函数自身。 自嵌套调用 函数自嵌套调用可以用作递归算法的实现。如果一种程序设计语言允许函数自嵌套调用,则一个函数就可以调用任何函数,包括自己。 从语法上看,函数调用自身并没什么特别,如果清楚函数定义与处于运行状态的函数之间的区别,理解静态代码段、活动记录、CIP、CEP等概念,那么理解函数递归调用的概念就不会存在困难,因为无论如何进行调用,无论调用的是否是函数自身,每进入一个函数时便为这次调用创建一个活动记录,并记录返回点的CIP和CEP,从被调函数退出时会删除当前的活动记录,恢复调用函数的活动记录,函数运行期间对局部变量及参数的访问都是针对当前活动记录中的数据对象进行的,如果是自嵌套,那么当前的变量不同于上次调用时的同名变量,它们所代表的是位于存储空间不同位置的同名数据对象,上一次调用过程中函数的局部变量在函数的本次调用中是不可见的。

  31. 5.4 相关的其它语法 5.4.1 数组作函数参数 5.4.2 函数指针

  32. 5.4.1 数组作函数参数 定义时函数参数用数组类型(该参数中可不指明数组所含元素数),调用函数时对应数组形参的位置以数组名作为实参。这种情况的形实结合属于传址调用,形参与实参共用内存中同一数组,调函数中改变某个元素的值,调用函数中相应数组元素的值也将改变。 [例5.14] 求数组元素的和。 1 .形参与实参都用数组 #include "iostream.h" int Sum(int nData[], int nNum, int nTest) { int nResult=0; if(nTest==0) { for(int i=0; i<nNum; i++) nData[i]=5-i; } else { for(int i=0; i<nNum; i++) nResult+=nData[i]; } return nResult; } void main() { int data[5]={1,2,3,4,5}; cout<<”The sum is ”<<Sum(data, 5, 1)<<endl; cout<<”The sum is ”<<Sum(data, 5, 0)<<endl; for(int i=0; i<5; i++) cout<<data[i]<<”, ”; cout<<endl; }

  33. 5.4.1 数组作函数参数 2. 形参与实参都用数组 由于数组与指针之间的天然联系,在需要用数组作为函数的参数时用指针来实现这一功能,因此就有三种可能的用法:形参和实参都用指针,形参用指针而实参用数组,形参用数组而实参用指针。 [例5.15] 分析下列程序输出结果。 #include "iostream.h" int Sum(int* pData, int nNum) { int nResult=0; for(int i=0; i<nNum; i++) nResult+=*(pData +i); return nResult; } void main() { int data[5]={1,2,3,4,5}; cout<<"The sum is "<<Sum(data, 5)<<endl; }

  34. 5.4.1 数组作函数参数 使用数组的引用要稍麻烦些,由于引用通常是对某种类型数据对象的引用,因此要使用数组的引用首先应该定义一个数组类型,然后再说明函数的参数为该类型的引用。 [例5.18] 分析下列程序输出结果。 3 .形参用数组名而形参用引用 #include "iostream.h" typedef int Array[5]; int Sum(Array& refArray, int nNum) { int nResult=0; for(int i=0; i<nNum; i++) nResult+=refArray[i]; return nResult; } void main() { int data[5]={1,2,3,4,5}; cout<<"The sum is "<<Sum(data, 5)<<endl; }

  35. 5.4.2 函数指针 函数在内存中是一段代码,有一个开始位置,每当函数被调用时,程序的控制就转移到这一点开始运行,C++中可以通过指向函数的指针指向某函数的起始地址,于是在程序中可以通过该指针调用这个函数。 1. 指向函数的指针 函数指针的说明格式: <ReturnType>(*pFunction)(<Arg_Type_List>); 可以使用函数指针指向具有相同类型参数及返回值的不同名字的函数。 void Func(char* str) { … … } void (*pFunc1)(char*)=&Func; void (*pFunc2)(char*)=Func; //Func与&Func的含义相同 void (*pFunc3)(char*); void Gunc() { … … pFunc3=&Func; // 也可以采用pFunc3=Func的函数指针赋值方式 pFunc1(”这是一种调用方式”); (*pFunc1)(”这是另一种调用方式”); … … };

  36. 5.4.2 函数指针 可参考如下方式定义指针类型: Typedef void (*OperationType)(); OperationType pOperation=&func; 2 . 函数指针类型 typedef int (*OperationType)(); OperationType FileMenuItemOperations[ ]={&FileOpen, &FileNew, &FileClose,...}; OperationType EditMenuItemOperatoins[ ]={&EditUndo, &EditCut, &EditPaste,...}; OperationType ViewMenuItemOperatoins[ ]={&ViewTile, &ViewMax, &ViewMini, ...}; main() { ... switch(nIndexMenuSelected) { case 0: FileMenuItemOperations[ nIndexSelectedItem ](); break; case 1: EditMenuItemOperatoins[ nIndexSelectedItem ](); break; ... } ... }

  37. 5.5 常用系统函数 编写程序是首先应该熟悉系统提供了哪些函数,本节所列仅为一些常用函数。 5.5.1终止程序运行 5.5.2 数学函数 5.5.3 字符串处理函数 5.5.4 面向对象的数据结构

  38. 5.5.1终止程序运行 void abort( void ); void exit( int status ); void _exit( int status ); 调用abort() 退出程序前弹出对话框,上面附有信息“abnormal program termination”,选择其上的“重试”按钮可对非正常终止的程序调试。 void main( void ) { fstream MyFile; MyFile.open("UnKonwnFile.txt", ios::nocreate); if(!MyFile ) { perror( "Couldn't open file" ); //在标准错误输出设备上输出错误信息 abort(); } else MyFile.close(); } 调用exit() ,程序终止前进行必要的清理工作,如清除atexit()注册的函数。而调用_exit()将立即中止程序运行而不做清理工作。

  39. 5.5.2 数学函数 文件math.h中定义了许多数学函数,下面所列为几个常用算术函数。 double sqrt(double x); //平方根 double sin(double x); //正弦 double power(double x, double y); //幂运算 double fabs(double x); //求绝对值 double abs(double x); //求绝对值

  40. 5.5.3 字符串处理函数 int strlen(const char* str); char* strcpy(char* dest, char* src); char* strcat(char* str1, char* str2); char *strchr( const char *string, int c ); int strspn( const char *string1, const char *string2 );

  41. 5.5.4 面向对象的数据结构 展示VC++的常用数据结构类

More Related