C++程序设计教程 第2章 过程的组织和管理

更新时间:2023-08-15 20:33:01 阅读量: 教学研究 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

第2章 过程的组织和管理

2.1 函数

2.1.1 函数结构和函数定义

一个大型的程序一般可以分成一系列“单一功能模块”的集合。在C++中,单一功能模块通常设计成一个函数。因而C++程序可以设计成一系列函数的组合,这是面向过程程序设计的一般方法。一个完整的C++程序一般包含一个主函数和若干个子函数,主函数可以调用子函数,子函数也可以调用其它的子函数。利用函数可以大大降低程序设计的工作量,使程序更加清晰可靠。很多编译系统本身就带有很多预定义的函数,并把它们以库函数的形式提供给用户,这大大方便了程序设计人员。函数定义的一般形式如下: 类型标识符 函数名(形参列表)

{

函数体;

}

类型标识符为函数的返回类型,可以是整型、浮点型等C++的合法类型,也可以是无值型(void型)。

函数名是函数的标识,可以是一个有效的C++标识符。

形参列表是括在圆括号内的0个或多个以逗号分隔的形式参数。它定义了函数将从调用函数中接收几个数据及它们的类型,所以称为形式参数。所谓形式参数的含义是指仅当函数被调用时,系统才为其分配存储空间。与之相应,主调程序传递过来的参数称之为实在参数。通常,形式参数和实在参数简称为形参和实参。

函数的返回值由返回语句return来实现。

例2.1.1

// filename:ex211.cpp

// 判断一个数是否素数

#include<iostream.h>

char prime(unsigned int number);

int main()

{

}

{

int m; cout<<"The primers from 3-100 are:"<<endl; for(m=3;m<=100;m++) if(prime(m)==1) cout<<m<<","; return 0; char prime(unsigned int number) char f=1;

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

} unsigned int n; for(n=2;n<=number/2;n++) if(number%n==0){ f=0; break; } return f;

2.1.2 函数名重载

函数名重载就是多个函数使用同一个函数名。

例2.1.2

// filename:ex212.cpp

// 判断两数较大者

#include<iostream.h>

int max(int x,int y);

double max(double x,double y);

int main()

{

cout<<max(10,20)<<endl; cout<<max(1.23,4.56)<<endl;

return 0;

}

int max(int x,int y)

{

} return x>y?x:y;

double max(double x,double y)

{

return x>y?x:y;

}

函数重载的好处是主调函数会根据参数自动选择正确的子函数,这大大提高了程序的通用性和可读性。

2.1.3 内嵌函数

程序在执行过程中,每调用一次函数,就要在调用与返回过程中付出一定的时间和空间代价用于处理现场,通常是用堆栈进行保护,返回时退栈恢复现场。但当函数较小,又反复使用时,处理现场的开销会急剧增大。若把函数嵌入函数调用处,便可以大大提高运行速度。这当然是以牺牲存储空间作为代价的。内嵌函数在程序编译时直接将代码嵌入到调用处,这增加了代码的长度,但运行速度大大加快。

例2.1.3

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

/// filename:ex213.cpp

// 判断两数较大者

#include<iostream.h>

inline double max(double x,double y);

int main()

{

int i; double a,b; for(i=1;i<3;i++) { cout<<"Enter two real:";

cin>>a>>b;

} cout<<max(a,b)<<endl; } return 0;

double max(double x,double y)

{

return x>y?x:y;

}

内嵌函数有如下限制:

(1) 内嵌函数中不能有循环结构或switch结构及goto语句;

(2) 内嵌函数中不能含有任何静态数据及数据声明。

由于有以上限制,使用起来不是太方便。因此,除非必要,一般尽量不使用内嵌函数。

2.1.4 递归函数

一个函数直接或间接调用自身,便构成了函数的递归调用。递归在程序设计中经常用到,它可以大大简化程序的设计。

例2.1.4 递归计算n!的函数。

int rfact(int n)

{

if(n<0){ cout<<“Negative argument.”<<endl; exit(-1); } else if(n==1) return 1; else return n*rfact(n-1);

}

递归过程不应无限制地进行下去,应当能在调用有限次以后,就到达递归调用的中点得到一个确定值,然后进行回代。回代的过程是从一个已知推出下一个值的过程。任何有意义

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

的递归总是由两部分组成,递归形式与递归终止条件。本例的算法就是基于如下的递归数学模型:

非法

fact(n) 1

n*fact(n 1) (n 1)(n 1) (n 1)

例 汉诺塔问题(Tower of Hanoi)。

// filename:hanio.cpp

// Tower of Hanoi

#include<iostream.h>

int hanoi(int number,char a[],char b[],char c[]);

int main()

{

int number;

cout<<"Please enter the number of disks to be moved:";

cout<<endl;

cin>>number;

hanoi(number, "PileA","PileB","PileC");

return 0;

}

int hanoi(int number,char a[],char b[],char c[])

{

if(number>0){

hanoi(number-1,a,c,b);

cout<<"Move disc "<<number<<" from "<<a<<" to "<<b<<endl;

} } hanoi(number-1,c,b,a); return 0;

2.1.5 C++库函数

C++语言的核心部分很小,其外壳却十分丰富。这个外壳中提供丰富的库函数。程序员使用库函数无须再自行定义,只要注意以下三点便可:

(1) 了解函数的功能

(2) 了解函数的原型

(3) 库函数按功能分为不同的库,每个库都有相应的头文件,给出了该库中各个函数的原型声明等有关信息。程序员使用库函数之前只需在程序中使用#include指令嵌入相应的头文件而不必再进行函数的原型说明。

//filename:ex215.cpp

#include<iostream.h>

#include<math.h>

int main()

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

{

float f;

cout<<“Enter a real number:”;

cin>>f;

cout<<“The square root of ”<<f<<“is: ”<<sqrt(f)<<endl;

} return 0;

库函数是一些被验证的、高效率的函数,进行程序设计时,应优先选用库函数。Visual C++提供了大量的库函数和宏,在程序中可以调用它们来执行各种各样的任务。它们包含有低级及高级的I/O、串及文件的操作、存储分配、进程控制、数据转换、数学运算等等。 Visual C++的库函数和宏包含在Lib子目录和Include子目录中。我们知道,调用函数前需要函数定义与函数声明。所有Visual C++库例程的原型在一个或多个库文件中声明。使用库函数时,用#include命令包含其相应的头文件就包含了其原型声明。使用头文件比直接写声明语句的一个好处是可以保证其正确性。系统头文件在Include子目录中,系统函数定义在Lib子目录中,连接时,系统将会根据原型到相应的库文件中连接相应的库例程,一般用户不必关心。Visual C++常用的库函数有以下一些:

字符分类函数

转换函数

目录管理函数

图形函数

输入输出函数 ctype.h ctype.h dir.h

graphics.h iostream.h、io.h、stdio.h、conio.h dos.h mem.h、string.h math.h、complex.h、bcd.h、float.h、stdlib.h alloc.h、dos.h stdlib.h、dos.h、locate.h process.h、signal.h 接口函数 串和内存操作函数 数学函数 内存分配函数 杂类函数 进程控制函数

文本窗口显示函数

时间、日期函数

其它 conio.h time.h、dos.h

2.2 程序实体及其存储类

程序实体也称程序对象,对应着程序中的一块内存空间。每个程序实体都有一个标识符,用以保存程序中用到的各种变量、标号、参数和函数等等。每个程序实体都有一定的作用域和生存期,这反映了它的存储属性。

2.2.1 程序实体的生存期和作用域

每个程序实体在程序执行中都有从创建到被撤消的一段时间,这段时间就称为该程序实体的生存期。在生存期内程序实体的标识符与它的存储区相关联。因此,程序实体的生存期由系统为其分配的内存方式所决定。C++为程序实体提供了四种内存分配方式:静态分配(编译器预分配)、栈分配(自动分配)、堆分配(动态分配)、只读分配。

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

(1) 静态分配

系统可以为每个程序开辟一个固定的静态数据区。存于这区域中的程序实体在编译时即被预分配存储空间,并且在程序开始执行时就被创建,一直到程序结束才被撤消,故称为永久存储。静态分配的特点是与程序共存亡,具有静态生存期。这种分配适合于那些在程序中用得不多,但要为多个函数共用的程序实体。

(2) 栈分配

栈是系统为程序开辟的活动存储区,它是程序使用最频繁的存储区。一个实体,一旦在一个函数内部或一个块内部被声明,系统便在栈中创建它们;该块或函数执行结束,遂将其弹出撤消。这种程序实体具有局部生存期,即它与所在的块共存亡。这种分配适合于那些在程序中使用频繁的程序实体,随建随撤,节省空间。

(3) 动态分配

动态分配将产生一种完全由程序员控制生存的程序实体。在C++中,程序员可以利用专门的运算符new和delete来创建和撤消程序实体。

(4) 只读分配

即用const声明的程序实体,可以认为是被创建在程序的只读存储区中。

作用域实际上就是程序实体的作用范围,而在此范围之外,该程序实体是不可见的。C++的这种特性使得在同一个程序中使用两个名字相同的程序实体成为可能,只要这两个程序实体的作用域不同就行。

2.2.2 C++的存储属性

存储属性是对作用域和生存期的抽象。C++的存储属性有以下四种:

auto(自动)

register(寄存器)

extern(外部)

static(静态)

在声明和定义程序实体时,可使用上述关键字来说明程序实体的存储属性。其格式为:

存储属性 类型 标识符=初始化表达式;

1. auto型

属于auto型的程序实体,称为自动程序实体,它采用的是栈分配存储模式。在C++中,auto可以不写,即程序实体的默认方式为auto。如:

auto int a; // 等价于int a

在C++中,以自动型变量用得最多,它的作用域具有局部属性,即从定义点开始至本函数(或块)结束。其生存期自然也随函数(或块)的销毁而销毁。因而通常称其为局部变量,具有动态生存期。

2. register型

register型程序实体和auto型程序实体的作用相同,只不过其采用的是寄存器存储模式,执行速度较快。当寄存器全部被占用后,余下的register型程序实体自动成为auto型的。只有整型程序变量可以成为真正的register型变量。

3. extern型

用extern声明的程序实体称为外部程序实体。它是为配合全局变量的使用而定义的。所谓外部变量,就是在块外保持不变,并不因块内发生变化而影响到块外。例如:

//filename:ex221.cpp

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

#include<iostream.h>

int a=7; // 定义全局变量

int main()

{

extern int a; //声明a引用的是全局变量,a=7

} cout<<a<<endl; { } extern int a; cout<<a<<endl;//a=7 return 0; int a=3;//屏蔽了全局变量a cout<<a<<endl;//a=3

由于使用外部变量容易造成程序员的混淆,故现在很少使用。在面向对象的程序设计语言中,更是不允许使用外部变量。

4. static型

用static声明的程序实体称为静态程序实体,它们有如下特点:

(1) 静态程序实体是永久存储,其生存期是静态的。它的初始化是在编译时进行的,在

整个程序运行期间,它都存在。

(2) 静态程序实体的生存期虽然是永久的,但其作用域却可以是局部的,当然也可以是

全局的。

//filename:ex222.cpp

#include<iostream.h>

void increment();

int main()

{

} increment(); increment(); increment(); return 0;

void increment()

{

}

表2.1 C++的存储属性

static int i;//永久生存期,局部作用域 i++; cout<<i<<endl;

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

2.3 编译预处理

C++语言允许在程序中用预处理命令写一些命令行。这些预处理行都以“#”打头,末尾不加分号以区别于语句行。它们可以出现在程序中的任何位置,但一般写在程序的头部。C++编译器在进行实质性的编译前,先要用它们的预处理程序对这些预处理命令行进行处理。C++提供的预处理命令有:

宏定义指令 #define

文件包含指令 #include

条件编译指令

行控制指令

其它 #if ... #else ...#end if #line 如 #pragma, #error

1. 宏定义

宏定义也称宏代换,实际就是用一个宏名字来命名一个字符串,其形式为: #define 宏名 宏体

下面是宏定义的一些例子:

#define EOF -1 //定义文件结束符

#define MAXIM 2147483647 //定义4字节最大值

#define

#define

#define

#define

#define

#define

#define TRUE FALSE 0 1 //定义逻辑真 //定义逻辑假 //取消DELETE宏定义 DELETE PI RADIUS CIRCUM CUBE(x) 3.1415926 2.0 return(2.0*PI*RADIUS) x*x*x

宏代换虽然很方便,增加了程序的可读性,但也同时会产生一些副作用。如函数调用时系统要进行参数类型检查,而宏调用没有内部类型检查,当实参与形参的类型不匹配时,会出现难以预料的结果 。

2. 文件包含

文件包含的作用是让编译器把一个已经进入系统的源文件嵌入到当前源文件中该指令处。它有两种格式:

#include<文件名> //编译器默认路径

#include“文件标识” //当前文件合法路径,可包含路径名

头文件中主要用来存放一些常量,常用数据结构,函数原型声明等等。这是模块化程序设计的一种有效的手段。

3. 条件编译

条件编译是源文件内系统级的选择结构,其格式如下:

#if 判断表达式

语句或预处理命令表列

#else

语句或预处理命令表列

#end if

使用条件编译可以有选择地对源程序中的部分代码进行编译,提高了代码的效率。条件编译常用于程序的调试过程。即在程序设计时为了便于检查程序是否有预想的中间结果或想

C++是在C语言的基础之上发展起来的。它既适合于编写面向过程的程序,也适合于编写面向对象的程序。在C语言推出之前,操作系统等系统软件主要是用汇编语言编写的。由于汇编语言依赖于计算机硬件,因此程序的可移植性和可读性就较差。但汇编语言也有它的好处,它能对硬件直接进行操作,速度快,效率高,一般高级语言没有这种功能。于是,1973年,贝尔实验室的Thompson和Ritchie开发了C语言,并用它重写了UNIX的大部分代码。C语言

了解程序执行的过程时,可以增加一些输出语句。使用条件编译可以使这些代码仅在调试过程中被编译。

本文来源:https://www.bwwdw.com/article/7soj.html

Top