返回 1
第 2章 C++语言基础本章是学习 C++语言的基础,包括以下几个方面:
1,结构化程序设计方法与面向对象程序设计方法的各自特点,
区别和相互联系 。
2,面向对象的程序设计方法中的有关概念,如类,对象,封装,继承,消息和多态性等 。
3,C++程序的基本组成和框架结构 。
4,掌握 C++语言中的基本数据类型,各种运算符,表达式 。
5,C++数据输入流对象 cin和输出流对象 cout的使用 。
6,程序的 3种基本结构
7,构造数据类型,如数组,结构体,指针等的定义方法,特点和使用方法 。
7,函数的定义,调用及函数调用过程中的参数传递的机理和程序执行流程 。
8,引用的概念及其定义和使用方法 。
返回 2
2.1 从面向过程的程序设计到面向对象的程序设计
2.1.1 传统的结构化程序设计( Structured Programming--
-SP)方法
1,使用 SP方法设计程序的步骤在数据处理过程中,采用的是自顶向下,分而治之的方法,将整个程序按功能划分为几个可独立编程的子过程模块,每一子模块完成指定的子任务,并且提供一个清晰,严格的调用界面,主过程通过调用各子过程完来成全部处理工作 。
数据声明 数据处理 结果输出返回 3
2,SP方法的特点优点:
( 1) 这种程序设计方法力求算法描述准确 。
( 2) 对每一子过程模块容易进行程序正确性证明 。
缺点:
( 1) 这种程序设计方法本质上是面向,过程,的,而
,过程,和,操作,又是不稳定和多变的,因此不能直接反映人类求解问题的思路 。
( 2) 程序代码可重用性差 。 程序中除少数标准库函数外,
每设计一个程序时,程序员几乎从零做起 。 即使重用代码,通常也是通过拷贝或编辑重新生成一份 。
( 3)维护程序的一致性困难。该种方法将数据与对数据进行处理的程序代码分离。
2.1 从面向过程的程序设计到面向对象的程序设计返回 4
2.1.2 面向对象的程序设计( Object-Oriented Programming
----OOP)方法
1,面向对象的有关概念面向对象的程序设计方法强调直接以问题域 ( 现实世界 ) 中的事物为中心来思考和认识问题,并按照这些事物的本质特征把它们抽象为对象,以作为构成软件系统的基础 。
( 1 ) 对象 ( Object ),每个对象都具有属性
( Attribute) 和方法 ( Method) 这两方面的特征 。 对象的属性描述了对象的状态和特征,对象的方法说明了对象的行为和功能,并且对象的属性值只应由这个对象的方法来读取和修改,两者结合在一起就构成了对象的完整描述 。
2.1 从面向过程的程序设计到面向对象的程序设计返回 5
( 2)类( Class),具有相似属性和行为的一组对象,
就称为类。可见,有了类的概念以后,就可以对具有共同特征的事物进行统一描述。
( 3)封装( Encapsulation),封装把对象的属性和方法看成了一个密不可分的整体,从而使对象能够完整地描述并对应于一个具体事物 。
( 4)继承( Inheritance),将客观事物进行归类是一个逐步抽象的过程,反之,将类进行层层分类便是一个概念逐渐细化的过程。
在面向对象的程序设计中,允许在已有类的基础上通过增加新特征而派生出新的类,这称为继承 。 其原有的类称为基类 ( base class),而新建立的类称为派生类 。
2.1 从面向过程的程序设计到面向对象的程序设计返回 6
( 5)消息( Message),在面向对象的程序设计中,由于对象描述了客观实体,它们之间的联系通过对象间的联系来反映。当一个对象需要另外一个对象提供服务时,它向对方发出一个服务请求,而收到请求的对象会响应这个请求并完成指定的服务。这种向对象发出的服务请求就称为消息。
( 6)多态性( Polymorphism),多态性是面向对象的另一重要特征。在通过继承而派生出的一系列类中,可能存在一些名称相同,但实现过程和功能不同的方法
( Method)。
所谓多态性是指当程序中的其他部分发出同样的消息时,按照接收消息对象的不同能够自动执行类中相应的方法。其好处是,用户不必知道某个对象所属的类就可以执行多态行为,从而为程序设计带来更大方便。
2.1 从面向过程的程序设计到面向对象的程序设计返回 7
2,面向对象的程序设计方法 ( OOP方法 )
这种方法将设计目标从模拟现实世界的行为转向了模拟现实世界中存在的对象及其各自的行为。
在 OOP中,将,对象,作为系统中最基本的运行实体,
整个程序即由各种不同类型的对象组成,各对象既是一个独立的实体,又可通过消息相互作用,对象中的方法决定要向哪个对象发消息、发什么消息以及收到消息时如何进行处理等。
2.1 从面向过程的程序设计到面向对象的程序设计方法数据 消息消息返回 8
3,OOP方法的特点
( 1) OOP以,对象,或,数据,为中心 。 由于对象自然地反映了应用领域的模块性,因此具有相对稳定性,可以被用作一个组件去构成更复杂的应用,又由于对象一般封装的是某一实际需求的各种成分,因此,某一对象的改变对整个系统几乎没有影响 。
( 2) 引入了,类,( class) 的概念 。 类与类以层次结构组织,属于某个类的对象除具有该类所描述的特性外,还具有层次结构中该类上层所有类描述的全部性质,OOP中称这种机制为继承 。
( 3) OOP方法的模块性与继承性,保证了新的应用程序设计可在原有对象的数据类型和功能的基础上通过重用、扩展和细化来进行,
而不必从头做起或复制原有代码,这样,大大减少了重新编写新代码的工作量,同时降低了程序设计过程中出错的可能性,达到了事半功倍的效果。
2.1 从面向过程的程序设计到面向对象的程序设计返回 9
2.1.3 面向对象的程序设计方法与结构化程序设计方法的比较
( 1) 传统的结构化程序设计方法以过程为中心构造应用程序,数据和处理数据的过程代码是分离的,相互独立的实体,设计出的程序可重用代码少,且当代码量增加时维护数据和代码的一致性困难 。
( 2) 面向对象程序设计方法中,对象所具有的封装性和继承性使得代码重用成为可能,并大大减少了程序出错的可能性 。
( 3) 面向对象方法吸收了结构化程序设计方法的优点,
同时引入了新概念,新机制并建立了比传统方法更高层次的抽象 。
2.1 从面向过程的程序设计到面向对象的程序设计返回 10
2.2.1 从 C语言到 C++语言
C语言以其如下独有的 特点 风靡了全世界:
( 1) 语言简洁,紧凑,使用方便,灵活 。 C语言只有 32
个关键字,程序书写形式自由 。
( 2) 丰富的运算符和数据类型 。
( 3) 可以直接访问内存地址,能进行位操作,使其能够胜任开发操作系统的工作 。
( 4) 生成的目标代码质量高,程序运行效率高 。
( 5) 可移植性好 。
2.2 C++程序的基本组成返回 11
2.2 C++程序的基本组成局限性,
( 1) 数据类型检查机制相对较弱,这使得程序中的一些错误不能在编译阶段被发现 。
( 2) C本身几乎没有支持代码重用的语言结构,因此一个程序员精心设计的程序,很难为其它程序所用 。
( 3) 当程序的规模达到一定程度时,程序员很难控制程序的复杂性 。
返回 12
2.2 C++程序的基本组成
C++包含了整个 C,C是建立 C++的基础 。 C++包括 C的全部特征和优点,同时添加了对面向对象编程 ( OOP) 的完全支持 。
1980年,贝尔实验室的 Bjarne Stroustrup开始对 C进行改进和扩充 。
1983年正式命名为 C++。
在经历了 3次 C++修订后,1994年制定了 ANSI C++ 标准的草案 。 以后又经过不断完善,成为目前的 C++。
C++仍在不断发展中 。 美国微软公司现已准备推出 C#( C
Sharp) 语言,来代替 C++语言 。
返回 13
2.2.2 C++程序的结构与基本组成一个简单的 C++程序,是由若干个函数构成的,其中有且仅有一个名称为 main的函数存在,下图说明了 C++程序的基本框架结构:
2.2 C++程序的基本组成声明区
#include<…… >
:
函数声明定义全局变量主程序区类型 main(参数行 )
{
程序主体;
}
函数定义区函数定义
{
函数主体;
}
返回 14
1,声明区声明区处在程序文件的所有函数的外部 。
( 1) 包含头文件:如 #include "iostream.h"
( 2) 宏定义:如 #define PI 3.1415926
( 3) 类定义:如 class name{ };
( 4) 结构体定义:如 struct record{ };
( 5) 函数声明:如 void print();
( 6) 全局变量声明:如 float H=2.58;
( 7) 条件编译:如 #ifdef 等 。
2.2 C++程序的基本组成返回 15
2,主程序区主程序以 main()函数开始,是整个程序运行的入口,该函数中可能包含的内容主要有:
( 1) 局部变量的声明:如,int i=1;
( 2) 函数调用:如,y=sin(x);
( 3) 一般运算:如,a=b+c+d/3;
( 4) 结构控制:如,if(a>b) c=a;
( 5) 对象与结构的处理 。
( 6) 文件的处理等 。
2.2 C++程序的基本组成返回 16
图 2.3 C++函数的组成
4,程序举例
2.2 C++程序的基本组成函数定义区函数说明 int max(int a,int b)
函数体
{
int c;
c=a+b;
return(c);
}
3,函数定义区程序中除了 main函数之外,还可以包含其它的函数,
每个函数是由函数说明和函数体两部分构成的。如图 2.3
所示:
返回 17
2.2 C++程序的基本组成声明区
#include "iostream.h"
#include "stdio.h"
void print(); //函数声明主程序区
void main()
{ int i;
char s[80];
print( );
cout<<"What's your name?\n";
cin>>s;
cout<<"How old are you?\n";
cin>>i;
cout<<s<<" is "<<i<<" years old.";}
函数定义区
void print( )
{
printf("printfis also can be used\n");
}
返回 18
上例程序结构可写为如下程序:
【 例 2-1】 一个简单的 C++程序 。
// This is first C++ program
/* C语言的某些特征仍可沿用 */
#include "iostream.h"
#include "stdio.h"
void print(); //函数声明
void main()
{ int i;
char s[80];
2.2 C++程序的基本组成返回 19
print( );
cout<<“What?s your name?\n”; // 用 C++特有的方式输出数据
cin>>s;
cout<<"How old are you?\n";
cin>>i;
//验证结果
cout<<s<<" is "<<i<<" years old.";
}
void print( )
{ printf("printf is also can be used\n");
}
2.2 C++程序的基本组成返回 20
从上例可以看出:
( 1) C语言中原有的规则和语句在 C++中仍可继续使用,
但 C++又增添了很多新的风格 。
( 2) 一个 C++的程序是由一到若干个函数构成的,但其中必须有且仅有一个名称为 main的函数存在 。
( 3) 不管一个程序中有多个函数,只有 main函数整个程序运行时的入口,程序运行时从此函数开始执行 。 但在程序中,main函数所处的位臵可以任意 。
( 4) 一个 C++的函数是由两部分构成的,即函数的说明部分和函数体,函数的说明部分包括了函数的返回值的类型,函数的名称,圆括号,形参及形参的类型说明 。
函数体由一对大括号 {}括起来,其内容是由若干条语句
2.2 C++程序的基本组成返回 21
构成,函数体的内容决定了该函数的功能 。
( 5) C++对程序中的名称是大小写,敏感,的,除特殊情况下,应一律小写 。
( 6) 程序中的注释:可以用 /*………… */或 //( 单行注释 ) 对程序中的内容进行注释 。 二者的区别在于,采用
/*………… */方法时,注释可以写成多行,而采用 //方法时,注释只能写成一行,它可单独占一行,也可写在某行程序代码的末尾 。
( 7) 数据输出:除了使用 printf( )函数,还可使用功能更强大,更方便的 cout对象进行输出数据 。 格式如下:
cout<<数据 1<< 数据 2<<…… << 数据 n
如:上例中的语句 cout<<s<<,is”<<i<<,years old.”; 表示同时输出了变量 s的值,字符串,is”,变量 i的值和字符
2.2 C++程序的基本组成返回 22
串,years old.”
(8) 数据输入:除了使用 scanf( )函数,还可使用功能更强大,更方便的 cin对象进行数据输入 。 格式如下:
cin>>变量 1>>变量 2>>…… >>变量 n
如:上例中的语句 cin>>s;表示给变量 s输入一个值
(9) 在分别使用 cout和 cin进行数据的输出和输入时,
需要在程序的开头嵌入,iostream.h”文件 。 在该头文件中定义了输入输出流对象 cout和 cin等 。
(10) 一个 C++的源程序文件在存盘时,要以,CPP为文件名后缀,而不是,C。
2.2 C++程序的基本组成返回 23
2.3 C++数据类型、运算符和表达式
2.3.1数据类型
( 1) 预定义数据类型 ( 基本数据类型 ) 。 包括字符型,
整型,浮点型,无值型四种,其中浮点型又分为单精度浮点型和双精度浮点型两种 。
( 2) 构造数据类型,包括数组,结构体,共用体 ( 联合 ),枚举,类等 。
本节重点介绍 C++的基本数据类型,有关构造数据类型将在后面章节进行介绍 。
返回 24
2.3.1.1 基本数据类型
2.3 C++数据类型、运算符和表达式数据类型 关键字 字节数 数值范围字符型 char 1 -128~ 127
整 型 int 4 -2147483648~ 2147483647
单精度浮点型 float 4 ± (3.4E-38~ 3.4E38)
双精度符点型 double 8 ± (1.7E-308~ 1.7E308
无值型 void 0 valueless
返回 25
2.3.1.2 类型修饰符
C++还允许在基本数据类型(除 void类型外)前加上类型修饰符,来更具体地表示数据类型。 C++的类型修饰符包括:
signed 有符号
unsigned 无符号
short 短型
long 长型
2.3 C++数据类型、运算符和表达式返回 26
数据类型标识符 字节数 数值范围 常量写法举例
Char 1 -128~ 127?A?,?0?,?\n?
signed char 1 -128~ 127 56
unsigned char 1 0~ 255 100
short [int] 2 -32768~ 32767 100
signed short [int] 2 -32768~ 32767 -3456
unsigned short [int] 2 0~ 65535 0xff
int 4 -2147483648 ~
2147483647
1000
signed int 4 -2147483648 ~
2147483647
-123456
unsigned int 4 0~ 4294967295 0xffff
表 2.2 C++的基本数据类型返回 27
数据类型标识符 字节数 数值范围 常量写法举例
long [int] 4 -2147483648 ~
2147483647
-123456
signed long [int] 4 -2147483648 ~
2147483647
-3246
unsigned long [int] 4 0~ 4294967295 123456
float 4 ± (3.4E-38~ 3.4E38) 2.35,-53.231,
3E-2
Double 8 ± (1.7E-308 ~
1.7E308)
12.354,-2.5E10
long double 10 ± (1.2E-4932 ~
1.2E4932)
8.5E-300
表 2.2 C++的基本数据类型返回 28
说明,
( 1) 表中带 [ ]的部分表示是可以省略的,如 short [int]可以写为 short int 或简写为 short,二者的含义是相同的 。
( 2) 四种修饰符都可以用来修饰整型和字符型 。 用 signed
修饰的类型的值可以为正数或负数,用 unsigned修饰的类型的值只能为正数 。
( 3) 用 short修饰的类型,其值一定不大于对应的整数,
用 long修饰的类型,其值一定不小于对应的整数 。
2.3 C++数据类型、运算符和表达式返回 29
2.3 C++数据类型、运算符和表达式
2.3.1.3 常量
在 C++语言中,数据分为常量和变量两大类 。
由于程序中的数据是有类型的,所以常量和变量都是有类型之分的 。。
常量按照不同的数据类型可以分为,字符型常量,整型常量,浮点型常量,以及字符串常量等 。
程序是根据程序中常量的书写格式来区分它是哪种类型常量的 。
返回 30
1.整型常量在程序中书写整型常量时,没有小数部分。用户可根据需要分别可以用十进制、八进制和十六进制的形式书写:
十进制格式,由数字 0至 9和正,负号组成,书写时直接写出数字,如,123,-516,+1000等 。
八进制格式,以数字 0开头的数字 ( 0至 7) 序列,
0111,010007,0177777等 。
十六进制格式,以 0x或 0X开头的数字 ( 数字 0至 9,字母 a至 z) 序列,如 0x78AC,0xFFFF等 。
2.3 C++数据类型、运算符和表达式返回 31
2.浮点型常量只能用十进制来表示 。 可以用小数或指数形式表示,不分单精度和双精度类型 。 如,34.5,,345,1.5e-3
3.字符型常量
( 1)用一对单引号括起来的一个字符,单引号只是字符与其他部分的分割符,不是字符的一部分,并且,不能用双引号代替单引号。在单引号中的字符不能是单引号或反斜杠。如:
a?,?A?,?#? 合法的字符常量
‘’’,?\? 非法的字符常量
,A” 不代表字符常量
( 2)另一种表示字符常量的方法是使用转义字符。
C++规定,采用反斜杠后跟一个字母来代表一个控制字符,
具有新的含义 。
2.3 C++数据类型、运算符和表达式返回 32
C++中常用的转义字符转义字符 含义 ASCII码值(十进制)
\a 响铃( BEL) 7
\b 退格( BS) 8
\n 换行( LF) 10
\r 回车( CR) 13
\t 水平制表( HT) 9
\v 垂直制表( VT) 11
\\ 反斜杠 92
\? 单引号 39
\” 双引号 34
\0 空格符( NULL) 0
\ddd 任意字符 3位八进制数
\xhh 任意字符 2位十六进制数
2.3 C++数据类型、运算符和表达式返回 33
4.字符串常量用一对双引号括起来的一个或多个字符的序列称为字符串常量或字符串。字符串以双引号为定界符,双引号不作为字符串的一部分。如:
,Hello”,,Good Morning!”,,I say,
\,Goodbye!\””
字符串中的字符数称为该字符串的长度,在存储时,
系统自动在字符串的末尾加以字符串结束标志,即转义字符 ‘ \0?。
5.符号常量常量也可用一个标识符来代表,称为符号常量。如,
#define PRICE 30
main()
{…… }
2.3 C++数据类型、运算符和表达式返回 34
使用符号常量应 注意 以下几个方面:
( 1) 它不同于变量,在作用域内其值不能改变和赋值 。
如:在上例中如再用 PRICE=40;这一语句进行赋值则是错误的 。
( 2)符号常量名一般用大写,而变量名用小写,以示区别。
6,程序中常量的表示方法在程序中的常量有以下三种表示方法:
( 1) 在程序中直接写入常量如,-200,3.4E-10,?A?,‘ 1?,0x120,045,5.35,1000l
int i; char s; float f;
i=20; s=?a?; f=2.0;
2.3 C++数据类型、运算符和表达式返回 35
( 2) 利用 #define定义宏常量一般格式,#define 宏名 常数如,#define PI 3.14
…………
s=2*PI*r;
…………
( 3) 利用 const定义正规常数一般格式,const 数据类型标识符 常数名 =常量值;
说明,
① const必须放在被修饰类型符和类型名前面
② 数据类型是一个可选项,用来指定常数值的数据类型,
如果省略了该数据类型,那么编译程序认为它是 int 类型
2.3 C++数据类型、运算符和表达式返回 36
如,const int a=10; 表示定义了一个初始值为 10的整型常量,它在程序中不可改变,但可用于表达式的计算中,
2.3.1.4 变量
1,变量的概念及特点每一变量就相当于一个容器,对应着计算机内存中的某一块存储单元,用于存储程序中的数据 。 变量的值具有以下两个特点:
( 1),一充即无,,即将一个新数据存放到一个变量中时,该变量中原来的值消失,变量的值变成了新值 。
如:执行完语句 int i; i=10; i=20;后 i的值为 20,而不是 10。
2.3 C++数据类型、运算符和表达式返回 37
( 2),取之不尽,,可将某个变量的值与程序中的其它数据进行各种运算,在运算过程中,如果没有改变该变量的值时,那么,不管用该变量的值进行多少次运算,
其值始终保持不变 。
如:语句 int i,j,k; i=10; j=i+10; k=i+j*5;其中,i的值可无限制地多次使用,但它的值始终保持值 10,因为在程序中没有改变变量 i的值。
2,定义变量程序中的每一变量,都要先定义,后使用 。
定义变量的一般有以下三种格式:
数据类型标识符 变量名;
数据类型标识符 变量名 =初始化值;
2.3 C++数据类型、运算符和表达式返回 38
数据类型标识符 变量名 1[=初始值 1],变量名 2[=初始值
2], ;
如:
char a; //定义字符型变量 a
int i=1000; //定义整型变量 i,i的初始值为 1000;
float a=2,b=3,c; //定义浮点型变量 a,b,c,且 a,b的初始值分别为 2,3。
变量名是每个变量的名称,其命名遵循以下规则:
( 1) 由字母,数字和下划线 ( _) 三类符号排列组合形成,且开头字符必须是字母或下划线 。
( 2) 名称中字符的最大个数是 31个 。
( 3) C++中区分变量名的大小写 。
2.3 C++数据类型、运算符和表达式返回 39
( 4) 变量名不能和 C++中的关键字同名,也不能和用户编制的函数或 C++库函数同名 。 如,int,double或 static都不能作为变量名 。
( 5) 变量名尽量做到,见名知意,。
3,定义变量的位臵在程序中的不同位臵采用不同的变量定义方式,决定了该变量具有不同的特点 。 变量的定义一般可有以下三种位臵:
( 1) 在函数体内部在函数体内部定义的变量称为局部变量,这种局部变量只在进入定义它的函数体时起作用,离开该函数体后该变量就消失 ( 被释放 ),即不再起作用 。 因此,不同函数体内部可以定义相同名称的变量,而互不干扰 。 如:
2.3 C++数据类型、运算符和表达式返回 40
void func1(void)
{ int y;
y=2;
}
void func2(void)
{ int y;
y=-100;
}
在本例中,函数 func1和 func2的函数体内部都分别定义了变量 y,但它们都只能在各自的函数体内起作用,都是局部变量 。
2.3 C++数据类型、运算符和表达式返回 41
( 2) 形式参数当定义一个有参函数时,函数名后面括号内的变量,统称为形式参数 。 如:
int is_in(char *a,char b)
{ while(*a)
if (*a==b)
return 1;
else
a++;
return 0;
}
本例中,函数名 is_in后面括号内的变量 a和 b是该函数的形式参数,
它们都只能在该函数体内起作用,是该函数的局部变量 。
2.3 C++数据类型、运算符和表达式返回 42
( 3) 全局变量,在所有函数体外部定义的变量,其作用范围是整个程序,并在整个程序运行期间有效 。 如:
#include,stdio.h”
int count; //定义 count变量是全局变量
void func1(void);
void func2(void);
int main()
{ count=10;
func1();
return 0; }
2.3 C++数据类型、运算符和表达式返回 43
void func1(void)
{ int temp;
temp=count;
func2();
printf(“count is %d”,count); / /输出 10
}
void func2(void)
{ int count;
for(count=1;count<10;count++)
putchar(?.?);
}
2.3 C++数据类型、运算符和表达式返回 44
2.3.2运算符和表达式程序中对数据进行的各种运算是由运算符来决定的,
不同运算符的运算方法和特点是不同的,从此可以看出,一个运算式子中要涉及到数据及运算符,而运算符是对数据进行指定操作,并产生新值的特殊符号 。
2.3.2.1 算术运算符和算术表达式算术运算符就是对数据进行算术运算,如:加、减、
乘、除等,是在程序中使用最多的一种运算符,C++
的算术运算符如表 2.4所示。
2.3 C++数据类型、运算符和表达式返回 45
运算符 功能 数据类型 例子
- 负号 数值 x=-y;
+ 加 数值 z=x+y;
- 减 数值 z=x-y;
* 乘 数值 z=x*y
/ 除 数值 z=x/y;
% 求余 整数 z=x%y
++ 自加 数值 z++或 ++z
表 2.4 C++的算术运算符
-- 自减 数值 z--或 --z
算术表达式是指由算术运算符,括号将常量,变量,函数,圆括号等连接形成的一个有意义的式子 。 如:
返回 46
(1+x)/(3*x)
(((2*x-3)*x+2)*x)-5
3.14*sqrt(r)
b*b-4.0*a*c
注意,
( 1) 表达式中的括号不管有多少层,一律使用圆括号 。
( 2) 在将一个数学上的运算式子写成对应的 C++的表达式时,要 注意 进行必要的转换 。
① 乘号不能省略 。
② 数学表达式中出现的数学运算函数要用 C++提供的对应的数学运算库函数来代替 。
2.3 C++数据类型、运算符和表达式返回 47
③ 要特别注意表达式中两个整型数相除的情况 。 如:
有一数学表达式为 2/3(f-32),要写成对应的 C++的表达式时,正确地写法应写 2.0/3.0*(f-32)。 而不是 2/3*(f-32)
2.3.2.2 赋值运算符和赋值表达式赋值运算符的功能将某个数据的值赋给某个变量 。
赋值运算符的用法格式:
变量名 赋值运算符 常量,变量或表达式说明:
( 1) 被赋值的目标,即赋值运算符左边的量必须是变量,而不能是常量或表达式 。
2.3 C++数据类型、运算符和表达式返回 48
( 2) C++中的赋值运算符如表 2.5所示 。
( 3) 要注意区分赋值运算符,=” 与数学上的,等号,
间的区别,如:
int x,y; //定义变量 x,y为 int类型变量
x=10; //将变量 x赋成值 10
赋值运算符 例子 等价形式
= x=x+y x=x+y
+= x+=y+z x=x+(y+z)
-= x-=y+z x=x-(y+z)
*= x*=y+z x=x*(y+z)
/= x/=y+z x=x/(y+z)
%= x%=y+z x=x%(y+z)
2.3 C++数据类型、运算符和表达式返回 49
x=x+20; //将 x的值在原值 ( 10) 的基础上再加上值 20后
( 结果为 30) 赋给变量 x
y-=x+5; //等价于 y=y-(x+5);右边表达式的值为 30-
(31+5)=-6,y被赋成值 -6
x%=y+10; //等价于 x=x%(y+10) ;右边表达式的值为
31%(-6+10)=3,y被赋成值 3
2.3.2.3 sizeof运算符
sizeof运算符功能是求某一数据类型或某一变量在内存中所占空间的字节数 。 其使用的一般形式:
sizeof(变量名或数据类型 )或 sizeof 变量名或数据类型如:
2.3 C++数据类型、运算符和表达式返回 50
#include <iostream.h>
void main()
{short int aShort;
int anInt;
long aLong;
char aChar;
float aReal;
cout<<"data type\tmemory used(bytes)";
cout<<"\nshort int\t"<<sizeof(aShort);
cout<<"\ninteger \t"<<sizeof(anInt);
cout<<"\nLong integer\t"<<sizeof(aLong);
cout<<"\nchar achar\t" <<sizeof(aChar);
cout<<"\nfloat \t"<<sizeof(aReal);
}
2.3 C++数据类型、运算符和表达式返回 51
其输出结果为:
data type memory used(bytes)
short int 2
integer 4
Long integer 4
char achar 1
float 4
2.3.2.4 关系运算符和关系表达式关系运算符就是对两个量之间进行比较的运算符,如表 2.6所示 。
2.3 C++数据类型、运算符和表达式返回 52
由关系运算符将两个表达式连接形成的运算式子是关系表达式,
一个关系表达式的值是一个逻辑值,当为真时,值为 1,为假时,值为 0。
如:假设 a=1,b=20,c=3,则
a<b 表达式成立,其值为 1
b==c 表达式不成立,其值为 0
(a+b)!=c表达式成立,其值为 1
关系运算符 含义 例子
< 小于 i>10
<= 小于或等于 (x+y)*2<=100
> 大于 x+y>z
>= 大于或等于 x-y>=a*b+2
= = 等于 x+y==a+b
!= 不等于 x-y!=0
2.3 C++数据类型、运算符和表达式返回 53
注意,
在对两个表达式的值进行是否相等的比较时,要用运算符
,==”,而不能写成,=” 。
2.3.2.5 逻辑运算符和逻辑表达式逻辑运算符是对两个逻辑量间进行运算的运算符,如表
2.7所示 。
2.3 C++数据类型、运算符和表达式逻辑运算符 含义 例子
! 逻辑非 !(x>10)
&& 逻辑与 (i>1) && (i<10)
|| 逻辑或 c==0 || c==9
返回 54
由逻辑运算符将两个表达式连接形成的式子叫逻辑表达式 。 各种逻辑运算的,真值表,如表 2.8所示 。 对于参加逻辑运算的操作数,系统认为,非 0” 为真,,0”
为假 。 而逻辑表达式的结果只能为逻辑真 ( 1) 或逻辑假 ( 0) 。
表 2.8 逻辑运算真值表
a b a&&b a||b !a !b
真 真 真 真 假 假真 假 假 真 假 真假 真 假 真 真 假假 假 假 假 真 真
2.3 C++数据类型、运算符和表达式返回 55
注意,
( 1) C或 C++中在给出一个逻辑表达式的最终计算结果值时,用 1表示真,用 0表示假 。 但在进行逻辑运算的过程中,凡是遇到非零值时就当真值参加运算,遇到 0值时就当假值参加运算 。 如,int a=10,b=15,c=14; 则 ( a+6)
&& (b>c)的值为 1( 真 ) 。
( 2) 在逻辑表达式的求值过程中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的值时,才执行该运算符 。
① a && b && c 只有 a为真时,才需要判别 b的值,只有 a
和 b的值都为真时才需要判别 c的值 。 如,int i=10;则表达式 i && (i=0) && (++i)的值为 0( 假 ),该表达式运算结束后,变量 i的值为 0,而不是 1。
2.3 C++数据类型、运算符和表达式返回 56
② a || b||c 只要 a为真,就不必须判断 b和 c;只有 a为假,
才判别 b; a和 b 都为假才判别 c。 如,int i=1,j; 则表达式
i++||i++||i++的值为 1( 真 ),运算结束后,变量 i的值为 2,
而不是 4。
③ 对于数学上的表示多个数据间进行比较的表达式,在
C或 C++中要拆写成多个条件并用逻辑运算符连接形成一个逻辑表达式 。 如:在数学上,要表示一个变量 a的值处于 -1和 -9之间时,可以用 -9<a<-1。 但在 C++语言中必须写成 a>-9 && a<-1,而不能写成 -9<a<-1。 因为,假设变量 a
当前的值为 -5,它的值确实处在 -1和 -9之间,但在 C++语言中求 -9<a<-1时,从左向右进行计算,先计算 -9<a,得 1
( 真 ),此时该表达式可简化为 1<-1,结果为 0( 假 ) 。
因此必须写成 a>-9 && a<-1的形式 。
2.3 C++数据类型、运算符和表达式返回 57
2.3.2.6 条件运算符在 C++中只提供了一个三目运算符 — 即条件运算符
,?,,,其一般形式为:
表达式 1? 表达式 2:表达式 3
条件运算的规则是:首先判断表达式 1的值,若其值为真
( 非 0),则取表达式 2的值为整个表达式的值;若其值为假 ( 0),则取表达式 3的值为整个表达式的值 。
如:若 a=3,b=4,则条件表达式 a>b?a:b的值为 4。
2.3.2.7 位运算符
1,位运算符及其运算规则所谓位运算符是指能进行二进制位运算的运算符 。 C++
提供的位运算符如表 2.9所示 。
2.3 C++数据类型、运算符和表达式返回 58
位运算的运算规则为:
( 1) 按位与 &:两个运算量相应的位都是 1,则该位的结果值为 1,否则为 0;
( 2) 按位或 |:两个运算量相应的位只要有一个是 1,则该位的结果值为 1,否则为 0;
运算符 含义 例子
& 按位与 i&128
| 按位或 j|64
^ 按位异或 j^12
~ 按位取反 ~j
<< 按位左移 i<<2
>> 按位右移 j>>2
2.3 C++数据类型、运算符和表达式返回 59
( 3) 按位异或 ^:两个运算量相应的位不同,则该位的结果值为 1,否则为 0;
( 4) 按位取反 ~:将运算量的每一位取反 。
( 5) 按位左移 <<:将操作数中的每一位向左移动指定的位数,移出的位被舍弃,空出的位补 0。
( 6) 按位右移 >>:将操作数中的每一位向右移动指定的位数,移出的位被舍弃,空出的位补 0或补符号位 。
如,a=5,b=6,则:
a 00000101 00000101 00000101
b &00000110 | 00000110 ^ 00000110 ~ 00000110
00000100 00000111 00000011 11111001
即,a&b=4,a|b=7,a^b=3,~b=249。
2.3 C++数据类型、运算符和表达式返回 60
2,复合位运算符位运算符与赋值运算符结合可以形成复合位运算符,
如表 2.10所示 。
2.3.2.8 强制类型转换运算符该运算符的功能是将某一数据从一种数据类型向另一运算符 例子 等价形式
&= x&=y+z x=x&(y+z)
|= x|=x+2 x=x|(x+2)
^= x^=y x=x^y
<<= x<<=y+z x=x<<(y+z)
>>= x>>=y+z x=x>>(y+z)
2.3 C++数据类型、运算符和表达式返回 61
种数据类型进行转换 。 其使用的一般形式:
数据类型标识符 ( 表达式 )
( 数据类型标识符 ) 表达式如,int i=2;
float a,b;
a=float(i); //将变量 i的类型强制转换为浮点型,并将其值赋给变量 a
b=(float)i; //将变量 i的类型强制转换为浮点型,并将其值赋给变量 b
2.3.2.9 逗号运算符逗号运算符的运算优先级是最低的 。 一般形式为:
表达式 1,表达式 2,,表达式 N
2.3 C++数据类型、运算符和表达式返回 62
在计算逗号表达式的值时,按从左至右的顺序依次分别计算各个表达式的值,而整个逗号表达式的值和类型是由最右边的表达式决定 。
如:有语句 int a=3,b=4;则表达式 a++,b++,a+b的值为 9。
再如:设有 int i;则表达式 i=1,i++==2?i+1:i+4的值为 6。
2.3.2.10 运算符的优先级与结合性每个运算符都有自己优先级和结合性 。 当一个表达式中包含多个运算符时,要确定运算的结果,必须首先确定运算的先后顺序,即运算符的优先级和结合性 。 C++中运算符的优先级和结合性如表 2.11所示 。
2.3 C++数据类型、运算符和表达式返回 63
优先级 运算符 结合性
1 ( ),,[] ->,,* ->* 自左至右
2 ! ~ ++ -- + - * & (类型 ) sizeof new[] delete[] 自右至左
3 * / % 自左至右
4 + - 自左至右
5 << >> 自左至右
6 < <= > >= 自左至右
7 == != 自左至右
8 & 自左至右
9 ^ 自左至右
10 | 自左至右
11 && 自左至右
12 || 自左至右
13?,自右至左
14 = += -= *= /= %= <<= >>= &= ^= |= 自右至左
15,自左至右表 2.11 C++中运算符的优先级和结合性返回 64
2.4 数据的输入与输出在 C++语言中,数据的输入和结果的输出是分别使用系统所提供的输入流对象 cin和输出流对象 cout来完成的 。
在使用过程中,只要在程序的开头嵌入相应的头文件
,iostream.h” 即可 。
2.4.1 数据的输出 cout
输出流对象输出数据的语句格式为:
cout<<数据 1<<数据 2<< <<数据 n;
说明:
( 1) cout是系统预定义的一个标准输出设备 ( 一般代表显示器 ) ;,<<” 是输出操作符,用于向 cout输出流中插入数据 。
( 2) cout的作用是向标准输出设备上输出数据,被输出的数据可以是常量,已有值的变量或是一个表达式 。
返回 65
如:
#include <iostream.h>
#include <math.h>
void main()
{ float a=3,b=4;
cout<< "The result is,";
cout<<sqrt(a*a+b*b); }
该程序的输出结果为,The result is,5
( 3) 可以在 cout输出流中插入 C++中的转义字符 。 如:
cout<< " the value of a:\n";
cout<<a;
2.4 数据的输入与输出返回 66
表示输出完字符串 Input the value of a:后,在下一行输出变量 a的值 。
( 4) 可以将多个被输出的数据写在一个 cout中,各输出项间用,<<” 操作符隔开即可,但要注意 cout首先按从右向左的顺序计算出各输出项的值,然后再输出各项的值 。
如,cout<<" value of a:"<<a<<" value of b:"<<b<<" The
result is,"<< sqrt(a*a+b*b);
再如:设变量 i的值为 10,则 cout<<i<<","<<i++<<","<<i++;
的输出结果为,12,11,10
( 5) 一个 cout语句也可拆成若干行书写,但注意语句结束符,;” 只能写在最后一行上 。 如:对于上面的语句也可写成如下形式:
2.4 数据的输入与输出返回 67
cout<<" value of a:" //注意行末无分号
<<a
<<" value of b:"
<<b
<<" The result is,"
<< sqrt(a*a+b*b); //在此处书写分号
( 6) 在 cout中,实现输出数据换行功能的方法:既可使用转义字符,\n”,也可使用表示行结束的流操作子 endl。
如:
cout<<"This is first Line.\n"<<"This is second line,";
上面语句可等价地写为:
cout<<"This is first Line."<<endl<<"This is second line,";
2.4 数据的输入与输出返回 68
( 7) 在 cout中还可以使用流控制符控制数据的输出格式,
但使用这些流控制符时,要在程序的头上嵌入头文件
#include <iomanip.h>。 常用的流控制符及其功能如表 2.12
所示 。
表 2.12 I/O流的常用控制符
2.4 数据的输入与输出控制符 功能
dec 十进制数输出
hex 十六进制数输出
oct 八进制数输出
setfill(c) 在给定的输出域宽度内填充字符 c
setprecision(n) 设显示小数精度为 n位
setw(n) 设域宽为 n个字符
setiosflags(ios::fixed) 固定的浮点显示返回 69
2.4 数据的输入与输出
setiosflags(ios::scientific) 指数显示
setiosflags(ios::left) 左对齐
setiosflags(ios::right) 右对齐
setiosflags(ios::skipws) 忽略前导空白
setiosflags(ios::uppercase) 十六进制数大写输出
setiosflags(ios::lowercase) 十六进制数小写输出
setiosflags(ios::showbase) 按十六/八进制输出数据时,前面显示前导符 0x/0;
返回 70
2.4 数据的输入与输出
① 设臵域宽:所谓域宽就是被输出数据所占的输出宽度
(单位是字符数)。设臵域宽可以使用流控制符 setw(n)
和 cout的方法 cout.width(n)
其中 n为正整数,表示域宽。但是,cout.width(n)和
setw(n)二者都只对下一个被输出的数据有作用,若一个输出语句内有多个被输出的数据,而要保持一定格式域宽时,需要在每一输出数据前加上 cout.width(n)或
setw(n)。
此外,当参数 n的值比实际被输出数据的宽度大时,
则在给定的域宽内,数据靠右输出,不足部分自动填充空格符;若被输出数据的实际宽度比 n值大时,则数据所占的实际位数输出数据,设臵域宽的参数 n不再起作用。
返回 71
【 例 2-2】 cout流控制符 setw的使用 。
#include <iostream.h>
#include <iomanip.h>
void main()
{int a=21,b=999;
cout<<setw(3)<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl; }
其输出结果是:
︼ 21︼ ︼ 21︼ ︼ ︼ 21 //程序中第一个 cout的输出结果
999︼ 999︼ ︼ 999 //程序中第二个 cout的输出结果
10201020︼ 1020 //程序中第三个 cout的输出结果
2.4 数据的输入与输出返回 72
② 设臵域内填充字符:在默认情况下,当被输出的数据未占满域宽时,会自动在域内靠左边填充相应个数的空格符 。 但我们也可以设臵在域内填充其他的字符,方法是利用 cout的 fill方法 cout.fill(c)或 setfill(c)。 cout.fill(c)上和 setfill(c)可以对所有被输出的数据起作用 。
【 例 2-3】 在例 2-2的基础上增加域内填充字符的功能 。
#include,iostream.h”
#include,iomanip.h”
void main()
{int a=21,b=999;
cout.fill(‘ #’ ); //设臵域内填充字符为 #字符
cout<<setw(3)<<a<<setw(4)<<a<<setw(5)<<a<<endl;
2.4 数据的输入与输出返回 73
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout.fill(‘ %’ ); //将域内填充字符改为 %字符
cout<<setw(3)<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
}
其输出结果是:
#21##21###21 //程序中第一个 cout的输出结果,未占满域宽的部分填充 #字符 。
999#999##999 //程序中第二个 cout的输出结果
10201020%1020 //程序中第三个 cout的输出结果,未占满域宽的部分填充 %字符 。
2.4 数据的输入与输出返回 74
当采用流控制符设臵填充字符时,上面程序代码也可等价地改为:
#include <iostream.h>
#include <iomanip.h>
void main()
{int a=21,b=999;
cout<<setw(3)<<setfill(‘ #')<<a<<setw(4)<<a<<setw(5)<<a
<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill(‘ %')<<a+b<<setw(4)<<a+b<<setw(5)
<<a+b<<endl;
}
2.4 数据的输入与输出返回 75
③ 设臵输出数据的进位计数制:在默认情况下,被输出的数据按十进制格式输出 。 但可以使用流控制符 hex和 oct控制数据的输出格式为十六进制和八进制,一旦设臵成某种进位计数制后,数据的输出就以该种数制为主,可利用流控制符 dec将数制重新成十进制 。
【 例 2-4】 在例 2-2的基础上增加域内填充字符的功能 。
#include <iostream.h>
#include <iomanip.h>
void main()
{
int a=21,b=999; //设臵以十六制格式输出数据
2.4 数据的输入与输出返回 76
cout<<setw(3)<<setfill('#')<<hex<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill(?%?)<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
//设臵以八制格式输出数据
cout<<setw(3)<<setfill('#')<<oct<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill('%')<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
//设置以十制格式输出数据
cout<<setw(3)<<setfill('#')<<dec<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill('%')<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
}
2.4 数据的输入与输出返回 77
程序的输出结果为:
#15##15###15 //以十六进制格式输出数据
3e7#3e7##3e7
3fc%3fc%%3fc
#25##25###25 //以八进制格式输出数据
17471747#1747
17741774%1774
#21##21###21 //以十进制格式输出数据
999#999##999
10201020%1020
2.4 数据的输入与输出返回 78
④ 设臵浮点数的输出格式:对于浮点数,既可以用小数格式输出,也可以用指数格式输出 。 这可以分别通过
setiosflags(ios::fixed)和 setiosflags(ios::scientific)来控制 。
【 例 2-5】 已知圆的半径 r=6.779,计算并输出圆的周长和面积,要求分别用指数和小数两种格式输出 。
#include <iostream.h>
#include <iomanip.h>
void main()
{ const double pi=3.14159;
double r=6.779,c,s;
c=2.0*pi*r; //计算圆的周长
s=pi*r*r; //计算圆的面积
2.4 数据的输入与输出返回 79
//以指数格式输出圆的面积和周长
cout<<"圆的周长 (指数 )为,"<<setiosflags(ios::scientific)<<c<<endl;
cout<<"圆的面积 (指数 )为,"<<s<<endl;
//以小数输出圆的面积和周长
cout<<"圆的周长 (小数 )为,"<<setiosflags(ios::fixed)<<c<<endl;
cout<<"圆的面积 (小数 )为,"<<setiosflags(ios::fixed)<<s<<endl;
}
程序的输出结果如下:
圆的周长 (指数 )为,4.259368e+001
圆的面积 (指数 )为,1.443713e+002
圆的周长 (小数 )为,42.5937
圆的面积 (小数 )为,144.371
2.4 数据的输入与输出返回 80
2.4.2数据的输入 cin
在 C++程序中,数据的输入通常采用 cin流对象来完成,
其格式如下:
cin>>变量名 1>>变量名 2>> >>变量名 n;
说明:
( 1) cin是系统预定义的一个标准输入设备
( 2) cin的功能是:当程序在运行过程中执行到 cin时,
程序会暂停执行并等待用户从键盘输入相应数目的数据,
用户输入完数据并回车后,cin从输入流中取得相应的数据并传送给其后的变量中 。
( 3),>>” 操作符后除了变量名外不得有其他数字,字符串或字符,否则系统会报错 。
2.4 数据的输入与输出返回 81
如,cin>>"x=">>x; //错误,因含有字符串 "x="
cin>>‘ x’ >>x; //错误,因含有字符 ‘ x=’
cin>>x>>10; //错误,因含有常量 10
( 4) cin后面所跟的变量可为任何数据类型,若变量为整型数据类型,则在程序运行过程中从键盘输入数据时,可分别按十进制,八进制或十六进制输入该整数 。 但要 注意,
当按十进制格式输入整数时,可直接输入数据本身即可;
若以十六进制输入整数时,数据前要冠以 0x或 0X;
若按八进制格式输入整数时,数据前要冠以数字 0,。
若 cin后面的变量为浮点类型 ( 单精度或双精度 ) 时,可分别按小数或指数的格式表示该浮点数 。
若 cin后面的变量为字符类型时,可直接输入字符数据而不能在字符的两端加单引号 。
2.4 数据的输入与输出返回 82
( 5) 当程序中用 cin输入数据时,最好在该语句之前用
cout输出一个需要输入数据的提示信息,以正确引导和提示用户输入正确的数据 。 如:
cout<< "请输入一个整数,"
cin>>x;
( 6) 当一个 cin后面同时跟有多个变量时,则用户在输入数据时的个数应与变量的个数相同,各数据之前用一个或多个空格隔开,输入完后按回车键;或者,每输入一个数据按回车键也可 。 如对于以下程序段:
int x;
double a;
char c1;
cout<<"输入一个整数,一个浮点数和一个字符,";
2.4 数据的输入与输出返回 83
cin>>x>>a>>c1;
cout<<"整数,"<<x<<"浮点数,"<<a<<"字符,"<<c1;
运行过程中,屏幕上显示,输入一个整数,一个浮点数和一个字符,”,用户输入数据的格式可以是:
100︼ 3.14︼ a
或者,100︼ ︼ ︼ ︼ 3.14︼ ︼ ︼ a
或者,100
3.14
a
最后程序的输出结果为,,整数,100浮点数,3.14字符,a”
2.4 数据的输入与输出返回 84
2.5.1 C++语句概述语句 ( statement) 是程序中最小的可执行单位 。 一条语句可以完成一种基本操作,若干条语句组合在一起就能实现某种特定的功能 。 C++中语句可以分为以下三种形式:
1,单一语句在任何一个表达式后面加上分号 ( ; ) 就构成了一条简单的 C++语句,例如:
c=a+b;
b++;
a>b?a:b;
cout<<,Hello C++” <<endl;等等 。
2.5 C++的控制语句返回 85
2,空语句仅由单个分号构成的语句,即;
称为空语句 。
空语句不进行任何操作 。 该语句被用在从语法上需要一条语句,但实际上却又不进行任何操作的地方 。
3.复合语句复合语句是用一对花括号 { }括起来的语句块 。 复合语句在语法上等效于一个单一语句 。
使用复合语句应 注意,
( 1) 花括号必须配对使用;
( 2) 花括号外不要加分号 。
2.5 C++的控制语句返回 86
2.5.2 C++程序的三种基本结构在程序设计中,语句可以按照结构化程序设计的思想构成三种基本结构,它们分别是顺序结构、分支结构和循环结构,如图 2.5所示。
顺序结构 分支结构 循环结构图 2.5 程序的三种基本结构
2.5 C++的控制语句语句 A
语句 B
条件
P
语句 A 语句 B
真假条件
P
语句 A
返回 87
1,顺序结构程序按照语句的书写顺序依次执行,语句在前的先执行,
语句在后的后执行,只能满足设计简单程序的要求 。
2,分支结构在分支结构中,程序根据判断条件是否成立,来选择执行不同的程序段 。 也就是说,这种程序结构,能有选择地执行程序中的不同程序段 。
3,循环结构在循环结构中,程序根据判断条件是否成立,来决定是否重复执行某个程序段 。
程序的执行流程和顺序是由程序中的控制语句来完成的,
而控制流程的主要方式是分支和循环 。
2.5 C++的控制语句返回 88
2.5.3 if 语句
if语句是最常用的一种分支语句,也称为条件语句 。 if
语句有三种形式:单分支 if 语句,双分支 if语句和多分支
if语句,如图 2.6所示 。
单分支 if 语句 双分支 if语句
2.5 C++的控制语句真假表达式语句真 假表达式语句 1 语句 2
返回 89
多分支 if语句
2.5.3.1 单分支 if 语句
if(表达式 )
语句真真真假假假表达式
1
表达式
2
语句 1 语句 2 语句 3 语句 4
2.5 C++的控制语句返回 90
其执行过程为:先计算关键字 if后面的表达式的值,若为真,则执行 if后的,语句,部分,否则跳过该,语句,部分 。 不管是否执行,语句,部分,最后都要接着,语句,
部分的后面,继续执行程序的其它部分 。
注意,
( 1) 括号不能省略 。
( 2) 在 if( 表达式 ) 后不能加分号,;,。
( 3) 关键字 if的后面的表达式可以是任意的表达式,只要表达式的值为非 0,即当真值处理,否则当假值处理 。
( 4) if语句的内嵌语句可以是单一语句,也可以是复合语句 。
( 5) 尽量使 if语句的内嵌语句比 if语句缩进,这是良好编程书写风格 。
2.5 C++的控制语句返回 91
如,int x=0,y=2;
if(x=0)
y++;
cout<<x<<y;
运算结束后,变量 y的值为 2,而不是 3,变量 x的值为 0。
2.5.3.2 双分支 if语句双分支 if语句的一般格式为:
if(表达式 )
语句块 1
else
语句块 2
2.5 C++的控制语句返回 92
其执行过程为:先判断表达式的值,若为真,则执行语句块 1,否则执行语句块 2。 不管程序执行语句块 1还是执行语句块 2,最后都要跳到语句块 2的后面接着执行程序中后面的语句 。
注意,
( 1) 语句块 1,语句块 2既可以是单一语句也可以是用 {}
括起来的复合语句 。
( 2) else子句必须与 if子句配对使用,不能单独使用 。
( 3) else子句必须处在 if子句的后面,且 else语句总是和离它最近的前面未配对的 if语句配对 。
【 例 2-6】 输入一个年号,判断是否为闰年,如果是则输出,yes”,否则输出,Not” 。
分析:只要满足下列两个条件之一者,即是闰年 。
2.5 C++的控制语句返回 93
① 年号能被 4整除,但要排除同时能被 100整除;
② 年号能被 400整除 。
#include <iostream.h>
void main()
{ int y;
cout<<"输入一个年号,";
cin>>y;
if ((y%4==0 && y%100!=0) || (y%400==0))
cout<<"Yes";
else
cout<<"Not";
cout<<"\n程序运行结束 ";}
2.5 C++的控制语句返回 94
2.5.3.3 多分支 if语句多分支 if语句是 if语句的嵌套结构,其一般形式为:
if(表达式 1)
语句 1
else if (表达式 2)
语句 2
else if (表达式 3)
语句 3
else if (表达式 N)
语句 N
else
语块 N+1
2.5 C++的控制语句返回 95
【 例 2-7】 输入学生的成绩 score,按分数输出其等级:
score≥90为优,90>score≥80为良,80>score≥70为中等,
70>score≥60为及格,score<60为不及格 。
#include<iostream.h>
void main()
{ float score;
cout<<"Input score(0~100):";
cin>>score;
if(score>=90)
cout<<"Excellent!";
else if(score>=80)
cout<<"Good!";
2.5 C++的控制语句返回 96
else if(score>=70)
cout<<"Right!";
else if(score>=60)
cout<<"Pass!";
else
cout<<"Failed!";
}
注意,在 if语句嵌套中 else与 if配对关系,else与离它最近的 if语句相匹配 。
2.5.4 switch语句
switch语句是多分支语句 。 在 C++中,使用 switch语句可以更方便,更简洁地实现多分支结构 。
2.5 C++的控制语句返回 97
switch语句的一般形式为:
switch(表达式 )
{ case 常数 1:语句 1; break;
case 常数 2:语句 2; break;
………………
case 常数 n:语句 n; break;
default,语句 n+1
}
switch语句的执行过程是:
① 计算 switch语句后面的表达式的值,当表达式的值与某一个 case后面的常量的值相等时,就执行此 case后面的语句,若所有的 case中的常量的值都没有与表达式的值相匹
2.5 C++的控制语句返回 98
配的,就执行 default后面的语句,当没有 default语句时,
则什么也不执行 。
② 执行完一个 case后面的语句后,程序执行的流程转移到下一个 case继续执行。,case 常量,只是起语句标号作用,
并不是在该处进行条件判断。在执行 switch语句时,根据
switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,不再进行判断。只有当遇到 break语句或执行完全部 switch内的语句时,才跳出 switch语句。
【 例 2-8】 输入学生的成绩 score,按分数输出其等级:
score≥90为优,90>score≥80为良,80>score≥70为中等,
70>score≥60 为及格,score<60 为 不 及 格 。
#include<iostream.h>
void main()
2.5 C++的控制语句返回 99
{ float score;
int a;
cout<<"Input score(0~100):";
cin>>score;
a=score/10;
switch(a)
{case 0:
case 9:cout<<"Excellent!";break;
case 8:cout<<"Good!";break;
case 7:cout<<"Right!";break;
case 6:cout<<"Pass!";break;
default:cout<<"Failed!"; }
}
2.5 C++的控制语句返回 100
说明:
① 常数 1~常数 n必须互不相同,且每一常数后面要有冒号
,:,;
② 各 case子句和 default子句的次序可任意;
③ 语句 1~语句 n+1可以为复合语句;
④ 在 switch语句中出现的 break语句并不是必需的,这要根据程序的需要来决定 。 在此 break语句的作用是跳出 switch
语句;
⑤ 各 case子句后面必须是常数,而不能是变量或表达式
2.5.5 循环语句
C++提供了三种循环结构,while循环语句,do-while循环语句和 for循环语句 。
2.5 C++的控制语句返回 101
2.5.5.1 while循环语句
while语句的一般形为:
while(表达式 )
{循环体语句 }
该语句的执行过程:首先判断 while后面的表达式的值,若表达式的值为真,则执行 while的内嵌语句
( 即循环体 ) 一次;然后重复以上过程,直到表达式的值为假时,才退出循环,接着执行循环体语句后面的其它程序语句 。
【 例 2-9】 求
2.5 C++的控制语句
100
1n
n
返回 102
#include<iostream.h>
void main()
{ int i,n;
n=0;
i=1;
while(i<=100)
{ n=n+i;
i++; }
cout<<"n="<<n<<endl;
}
2.5.5.2 do-while 循环语句
do-while语句的一般形式为:
2.5 C++的控制语句返回 103
do
{
循环体语句
} while(表达式 );
该语句的执行过程:首先执行 do-while的内嵌语句(循环体语句)一次,然后再判断 while后面的表达式的值,
若表达式的值为真,则重复执行 do-while的内嵌语句,如此反复,直到表达式的值为假时,循环结束,执行 while
后面的语句。
【 例 2-10】 求
#include<iostream.h>
void main()
2.5 C++的控制语句
100
1n
n
返回 104
{ int i,n;
n=0;
i=1;
do {n=n+i;
i++;}
while(i<=100);
cout<<"n="<<n<<endl;
}
说明:在循环体相同的情况下,while语句和 do-while
语句的功能基本相同 。 二者的区别在于:当循环条件一开始就为假时,do-while语句中的循环体至少会被执行一次,而 while语句则一次都不执行 。
2.5 C++的控制语句返回 105
2.5.5.3 for循环语句
for循环语句的一般格式为:
for(表达式 1;表达式 2;表达式 3)
{ 循环体语句 }
该语句的执行过程是:
① 执行 for后面的表达式 1;
② 执行表达式 2,若表达式 2的值为真,则执行 for语句的内嵌语句 ( 即循环体语句 ),然后执行第 ③ 步,若为假,
则循环结束,执行第 ⑤ 步;
③ 执行表达式 3;
④ 返回继续执行第 ② 步;
⑤ 循环结束,执行 for语句的循环体下面的语句 。
2.5 C++的控制语句返回 106
【 例 2-11】 求 。 用 for语句实现循环 。
#include<iostream.h>
void main()
{ int i,n;
n=0;
for(i=1;i<=100;i++)
n=n+i;
cout<<"n="<<n<<endl; }
2.5.5.4 循环嵌套在一个循环的循环体中又包含另一个循环语句,称为循环嵌套。 C++的三种循环语句可以相互嵌套,构成循环
2.5 C++的控制语句
100
1n
n
返回 107
嵌套 。 以下几种都是合法的循环嵌套:
( 1) for(;;)
{
……
for(;;)
{ }
……
}
( 2) while()
{
……
for(;;)
{ }
do{
……
}while( );
……
}
2.5 C++的控制语句返回 108
( 3) do{
……
for(;;)
{ }
……
}while( );
同样,if语句和 switch语句也可以与这三种语句嵌套使用。
注意,
( 1)循环嵌套时,外层循环和内层循环间是包含关系,
即内层循环必须被完全包含在外层循环中,不得交叉。
( 2)当程序中出现循环嵌套时,这时,程序每执行一次外层循环,则其内层循环必须循环所有的次数(即内层
2.5 C++的控制语句返回 109
循环结束)后,才能进入到外层循环的下一次循环。
2.5.5.5 限定转向语句
C++提供了跳转语句 break和继续语句 continue。
1,break语句
break语句的一般形式为:
break;
该语句只能用于两种情况:
( 1) 用在 switch结构中,当某个 case子句执行完后,使用
break语句跳出 switch结构 。
( 2) 用在循环结构中,用 break语句来结束循环 。 如果在嵌套循环中,break语句只能结束其所在的那层循环 。
2.5 C++的控制语句返回 110
【 例 2-12】 任意输入若干个整数 ( 不多于 50个 ),计算已输入整数之和,直到输入了负数为止 。
#include <iostream.h>
void main()
{ int i,n,sum;
sum=0;
for(i=0;i<=50;i++)
{ cout<<"\nInput number:";
cin>>n;
if(n<0)
break;
2.5 C++的控制语句返回 111
sum+=n; }
cout<<"sum="<<sum<<endl;
}
2.continue语句
continue语句的一般形式为:
continue;
该语句只能用在循环结构中 。 当在循环结构中遇到
continue语句时,则跳过 continue语句后的其他语句结束本次循环,并转去判断循环控制条件,以决定是否进行下一次循环 。
【 例 2-13】 输出 0~ 100之间所有不能被 3整除的数 。
2.5 C++的控制语句返回 112
#include<iostream.h>
void main()
{ int i;
for(i=0;i<=100;i++)
{ if(i%3==0)
continue;
cout<<i<<endl;}
}
2.5.5.6 三种循环的比较
( 1)三种循环可以相互代替;且都可以使用 break和
continue语句限定循环转向;
( 2) while语句和 for语句是先判断条件,后执行循环体,
而 do-while语句是先执行循环体,后判断条件;
2.5 C++的控制语句返回 113
( 3) for语句功能最强,可完全取代 while和 do-while语句;
( 4) while和 do-while语句中循环变量初始化应该在循环前提前完成,并在 while后指定循环条件,循环体中要包含使循环趋于结束的语句,而 for循环可把这些操作放在 for语句当中 。
2.6 数组及其使用前面已经讲过基本数据类型,如,整型,字符型,实型等,
C++语言还提供了构造数据类型,如,数组,结构体,联合体等,有的书中也叫,导出数据类型,,本节先介绍数组 。
数组是由若干相同数据类型的数据所组成的有序集合。
数组中每一个数据又称为数组元素,它们之间具有固定的先后顺序。用一个统一的数组名和下标来唯一地确定数组中的元素。
2.5 C++的控制语句返回 114
2.6 数组及其使用凡是具有一个下标的数组称为一维数组,具有两个或两个以上下标的数组称为多维数组。
2.6.1 一维数组
2.6.1.1 一维数组的定义一维数组定义的一般格式为:
类型说明标识符 数组名 [常量表达式 ];
如,int b[5];
对定义作几点说明,
( 1) 数组名的命名遵循 C++语言标识符的命名规则;
( 2) 数组名后边是用 [ ]括起来的常量表达式,而不能用圆括号 。
返回 115
( 3) 常量表达式表明该数组的长度,即数组中元素的个数 。 如,int b[5];表示 b数组中共有 5个元素 。
( 4) 常量表达式中可以包括常量和符号常量,不能为变量,
即不允许对数组的大小作动态定义 。 如以下定义不正确,
int n;
scanf(“%d”,&n);
int a[n];
2.6.1.2 一维数组的引用一维数组中各元素在内存中所占的存储单元按下标序号顺序存放,C++语言规定,只能逐个引用数组中的元素,
而不能一次引用整个数组,而数组元素的表示形式为:
数组名 [下标 ]
2.6 数组及其使用返回 116
【 例 2-14】 定义一个一维数组,把各元素值清 0,并输出各元素值 。
#include <iostream.h>
void main()
{ int i;
int b[5];
for(i=0;i<=4;i++)
b[i]=0;
for(i=4;i>=0;i--)
cout<<b[i]<<endl;
}
2.6 数组及其使用返回 117
2.6 数组及其使用
2.6.1.3 一维数组的初始化可以用赋值语句或输入语句使数组中的元素得到值,
也可以使数组在运行之前初始化,即在编译阶段使之得到初值,可用以下几种方法:
(1)在定义数组时对数组元素赋以初值,如,
int a[5]={0,1,2,3,4};
将数组元素的初值放在一对大括号内,各值之间用逗号隔开 。 定义后的结果为,a[0]=0,a[1]=1,a[2]=2,a[3]=3,a[4]=4
(2)可以只给一部分元素赋值,如:
int a[5]={0,1,2};
这说明 a 数 组 中 5 个 元 素 只 有 3 个 元 素 赋 初 值 。
即,a[0]=0,a[1]=1,a[2]=2,后两个元素的值为 0。
返回 118
(3)如果想使一个数组中全部元素值为 0,可以写成
int a[5]={0,0,0,0,0};
(4)在对全部元素赋初值时,可以不指定数组的长度 。 如,
int b[5]={0,1,2,3,4};
可写成:
int b[]={0,1,2,3,4};
2.6.2 二维数组
2.6.2.1 二维数组的定义二维数组定义的一般形式为,
类型说明符号 数组名 [常量表达式 ][常量表达式 ]
如,int a[3][4]; 这就定义了一个 3*4(3行 4列 )的数组 。
2.6 数组及其使用返回 119
注意,不能写成 int a[3,4];的形式 。
如,int a[3][4];
可以把它看作是一个一维数组,它有 3个元素 a[0],a[1],a[2],
这每个元素又是一个分别含 4个元素的一维数组:
a[0] a[0][0],a[0][1],a[0][2],a[0][3]
a a[1] a[1][0],a[1][1],a[1][2],a[1][3]
a[2] a[2][0],a[2][1],a[2][2],a[2][3]
C++语言中,二维数组中元素在计算机内存中的存放顺序是:按行存放,即先在内存中存放第一行的元素,再放第二行的元素,如:
a[0][0],a[0][1],a[0][2],a[0][3],[1][0],a[1][1],a[1][2],a[1][3]等
2.6 数组及其使用返回 120
2.6.2.2 二维数组的使用二维数组元素的表示方式为:
数组名 [下标 ][下标 ]
注意 下标不要超过各维的大小。
2.6.2.3 二维数组的初始化对于二维数组有下列初始化方法:
( 1) 分行给二维数组赋初值,如:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
这种赋值方法比较直观,把第一对括号内的数值赋给第一行的元素,第二括号内的数值赋给第二行的元素,
依此类推 。
2.6 数组及其使用返回 121
( 2) 可以将所有数据写在一个花括号内,这时,计算机自动按数组元素在内存中的排列顺序对各元素赋初值 。
如 int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
( 3) 可以只对数组中部分元素初始化 。 如:
int a[3][4]={{1},{5},{9}};
此处的作用表示,a[0][0]元素被赋成 1,a[1][0]元素被赋成
5,a[2][0]元素被赋成 9,而数组中的其他元素被初始化为 0。
( 4) 如果对二维数组的全部元素初始化,则定义数组时第一维长度可以省略,但第二维长度不能省,如:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
可写成,int a[ ][4]=1,2,3,4,5,6,7,8,9,10,11,12};
也可以只对部分元素初始化而省略第一维的长度,但应
2.6 数组及其使用返回 122
分行进行初始化,如:
int a[][4]={{0,0,3},{},{0,10}};
2.6.3 字符数组
1,字符数组的定义用来存放字符型数据的数组为字符数组,数组中的一个元素中只能存放一个字符,整个数组可以存放一个字符串 。。
如,char c[5];
2,字符数组的初始化字符数组的初始化方式同一维数组的初始化类似,如:
char c[5]={?a?,?b?,?c?,?d?,?e?};
3,字符和字符串结束标志:
2.6 数组及其使用返回 123
在 C++语言中字符串是以 ‘ \0?代表结束标志 。
如:,C.program”是 9个字符的字符串,但在内存中占
10个字节,最后一个字节存放 ‘ \0?。
注意,字符串只能用字符数组来保存,不能用一个简单的字符变量保存,另外,字符数组的初始化方式也可写为,char c[10]={“C.program”};
4,字符串的输出:
对于字符串的输出可以采用下列方法来完成:
( 1) 用 cout,格式是:
cout<<字符串或字符数组名;
如:设有,char s[20]={"This is a string."};则 cout<<s;的输出结果为 This is a string.。
也可直接输出字符串,如,cout<<"This is a string."
2.6 数组及其使用返回 124
( 2) 用 cout流对象的 put方法,格式是:
cout.put(字符或字符变量 );
利用这种方法,每次只能输出一个字符,所以要输出整个字符串,应采用循环的方法 。 如:
#include <iostream.h>
void main()
{ char s[20]={"This is a string."};
int i=0;
while (s[i]!='\0')
{ cout.put (s[i]);
i++;
}
}
2.6 数组及其使用返回 125
( 3) 用 cout流对象的 write方法,格式是:
cout.write(字符串或字符数组名,个数 n);
其作用是输出字符串中的前 n个字符 。 如:
#include <iostream.h>
void main()
{ char s[20]={"This is a string."};
cout.write(s,4); }
该程序的输出结果为 This
5,字符串的输入:
除了可以在程序中利用字符数组初始化的方法或赋值方法将字符串存放到字符数组外,还可以采用以下方法,
但要注意,只能用字符数组接收输入的字符串。
2.6 数组及其使用返回 126
( 1) 利用 cin直接输入 。 格式是:
cin>>字符数组名;
如:
#include <iostream.h>
void main()
{ char s[20];
cin>>s;
cout<<s; }
当程序运行时,输入 abcde并回车时,则输出结果为
abcde,但当输入 ab cde时,输出结果为 ab。因此,这种方法输入字符串时,cin只能接收空格符之前的部分。无法完成接收全部的字符串。
2.6 数组及其使用返回 127
( 2) 利用 cin流对象的 getline方法 。 格式是:
cin.getline(字符数组名,输入字符串的最大长度 n);
其中:
① 参数,字符数组名,是存放字符串的数组名称;
② 参数,输入字符串的最大长度 n” 包括字符串结束标记
\0在内 。 如:
#include <iostream.h>
void main()
{ char s[20];
cin.getline (s,20);
cout<<s; }
2.6 数组及其使用返回 128
当程序运行过程中输入 abcdef并回车时,程序的输出结果为 abcdef。 而当输入 ab cdef回车时,程序的输出结果为 ab cdef。 由此可见,该种方法可以接收含有空格符的字符串 。
( 3) 利用 cin流对象的 get方法 。 格式是:
格式 1,cin.get(字符数组名,输入字符串的最大长度 n);
格式 2,[字符变量名 =]cin.get();
说明:
① 格式 1中的两参数的含义同 getline方法 。
② 格式 2表示输入一个字符,如果要保存该字符,则在其左边写上被赋值的变量名和赋值号,如果不保存该字符,
则可写为 cin.get();
2.6 数组及其使用返回 129
#include <iostream.h>
void main()
{ char s[20];
char c;
cin.get(s,10);
cout<<s;
c=cin.get();
cout<<c; }
当程序运行过程中输入 ab cdef并回车时,程序的输出结果为 ab cdef和换行。由此可见,字符串 ab cdef被接收到字符数组 s中,而输入过程中的换行符 \n被接收到了变量 c
中。这说明输入过程中的换行符 \n并未接收,而还残留在输入缓冲区中。这一点也是 cin.get与 cin.getline间的区别。
2.6 数组及其使用返回 130
一个 C++程序是由若干个源程序文件构成的,而一个源程序文件是由若干个函数构成 。
从用户的角度看,有两种不同的函数:库函数和用户自定义函数 。 所谓库函数也称标准函数,由 C++系统提供 。
而用户自定义函数则需要用户先定义,后使用 。
2.7.1 函数的定义
2.7.1.1 函数的定义格式定义函数的一般形式:
函数返回值的数据类型标识符 函数名 ( 形式参数表及其类型 )
{函数体 }
2.7 函数返回 131
2.7 函数如:
void display_larger( int x,int y)
{
if (x<y)
cout<<"The larger is,"<<y<<"\n";
else if(x>y)
cout<<"The larger is,"<<x<<"\n";
else
cout<<"Two values are equal,"<<"\n";
}
返回 132
在 C++中定义函数时 注意,
( 1) 函数的形参及类型说明要采用新的 ANSI标准,即必须放在函数名后面的括号内 。
( 2) 当形参有多个时,必须用逗号隔开 。
( 3) 如果函数是无参函数,括号也不能省略 。
( 4)所有的函数都要先定义,后使用(调用)。
( 5)不能省略函数值的类型,必须表明该函数的函数值的类型,即使该函数没有返回值,也要注明函数值的类型为 void。
2.7 函数返回 133
2.7.1.2 函数的参数和函数的返回值;
所谓调用函数是指在程序中使用了该函数。
主调函数被调函数调用点
1,形式参数和实际参数 ( 形参和实参 )
在调用函数时,大多数情况下,主调函数和被调函数之间有数据传递关系。而函数之间的数据传递就是靠函数的参数进行的,而对无参函数的调用,没有数据传递
2.7 函数返回 134
在定义函数时,函数名后面括号内的变量名为,形式参数,( 形参 ) 。 在调用函数时,函数名后面括号内的表达式为,实际参数,( 实参 ) 。
例,void main()
{int a,b,c;
cin>>x>>y;
c=max(a,b);
cout<<“max is”<<c; }
int max(int x,int y)
{ int z;
z=x>y?x:y;
return(z); }
2.7 函数返回 135
关于形参和实参说明几点:
( 1) 实参可以是变量,常量,或表达式,但必须有确定的值 。 而形参必须是变量 。
( 2) 形参变量,只有存在发生函数调用时,形参才被分配存储单元,在调用结束时,形参所占的内存单元被释放 。
( 3) 实参与形参的类型必须一致,否则会发生,类型不匹配,的错误 。
( 4) 实参对形参的数据传递是,值传递,,即单向传递 。
由实参把数据传给形参,并且存储单元与形参是不同的单元,并将实参对应的值依次传递给形参变量 。 调用结束后,形参单元被释放,而实参单元保留并维持原值 。
2.7 函数返回 136
2,函数的返回值:
( 1) 函数的返回值是通过函数中的 return语句获得的,
return语句的格式为:
return(表达式 );或 return 表达式;
return语句的功能有两个,
(A) 强制程序执行的流程从被调函数返回到主调函数
(B) 给主调函数带回一个确定的函数值如,int max(int a,int b)
{ return(a>b?a:b); }
2.7 函数返回 137
( 2) 函数值的类型:函数返回值的类型就是在定义函数时的函数值的类型 。 在定义函数时,函数值说明的类型和 return语句中的表达式类型不一致时,则以函数类型为准 。
( 3) 如果被调用函数中没有 return语句,为了明确表示函数,不返回值,,要用 viod定义无类型 。
如,viod print()
{ printf(“c language”);
}
这样系统就保证不使函数带回任何值。
2.7 函数返回 138
2.7.2 函数的调用
1,函数调用的格式函数名 ( 实参数 )
如果调用的是无参函数,则实参表可略去,但函数的括号不能省,
如果实参表中有多个参数,之间用逗号隔开,实参的类型,个数应与形参顺序一一对应 。
函数通过下列三种方式完成函数调用:
( 1) 函数调用语句:即以一个函数的调用后面加上,;,
作为一个语句 。 如,printf();
( 2) 函数表达式:即函数出现在一个表达式中,这时要求函数带回一个确定的值以参加表达式的运算 。 如:
c=2*max(a,b);
2.7 函数返回 139
( 3) 函数参数:以函数的调用作为一个函数的实参 。 如:
M=max(a,max(b,c));
2.调用函数时的前提条件在一个函数中调用另一个函数,需要具备的条件:
( 1) 首先被调用的函数必须已经存在的函数 。 如果调用库函数,一般还应在本文件的开头用 #include命令将调用有关库函数时所需用到的信息包含到本文件来 。
( 2) 如果调用用户自己定义的函数,则必须对被调函数的原型进行说明,函数的原型包括:
函数值的类型标识符 被调用函数名 ( 形参及其类型表 ) ;
( 3) 对函数原型的说明,通常放在程序的顶部,也可以存放到一个头文件中,然后利用 #include 语句嵌入到程序中 。
2.7 函数返回 140
3.函数的定义与函数调用间的区别
( 1) 函数的,定义,是一个函数功能的确立,包括指定函数名,函数返回值的类型,形参及其类型,函数体等,
它是一个完整的,独立的函数单位 。
( 2) 函数的,说明,则只是对已经定义好的函数的返回值进行类型的说明,它包括函数名,函数类型和一对括号 。 而不包括形参和函数体 。
( 3) 对函数进行说明的作用是告诉系统,在本程序中将要用到的函数是什么类型,以便在主调函数中按此类型对函数值作相应的处理 。
2.7 函数返回 141
2.7.3 函数的嵌套调用
C++语言中函数的定义是平行的,独立的,所以,函数的定义是不能嵌套进行的,但函数的调用可以 。 嵌套调用即在调用一个函数的过程中,又调用另一函数 。
2.7 函数
main()函数
{
调用 a函数
}
a( )函数
{
调用 b函数
}
b( )函数
{
}
返回 142
在本例中,main函数在执行过程中,调用了函数 a,而函数 a中又调用了函数 b,所以,这就是一种嵌套调用 。
要 注意,在函数嵌套调调用过程中程序执行的流程和返回点的问题 。
2.7 函数返回 143
2.7 函数
2.7.4 函数的递归调用
1,函数递归调用的概念函数的递归调用就是当一个函数在执行的过程中,出现了直接或间接地调用函数本身的函数调用方式 。
下面定义求 n!的函数 。
long fact(long n)
{ if (n==1)
return 1;
return fact(n-1)*n; //出现了函数 fact自己直接调用本
} 身的函数调用要正确地理解函数的递归调用时,程序执行的流程和返回点 。
返回 144
2.7 函数
2,函数递归调用的条件递归调用的条件也是我们在定义一个递归函数时应该遵循的原则 。
( 1) 必须有完成函数任务的语句 。 如:上例求 n!中的
return 1;
( 2) 有一个确定是否能避免递归调用的测试条件 。 如果条件不满足时就递归调用,否则就不再递归调用 。
( 3) 有一个递归调用语句,并且该递归调用语句的参数应该逐渐逼近不满足条件,以致最后断绝递归 。
( 4) 先测试,后递归调用 。 在递归函数定义中,必须先测试,后递归调用 。 也就是说,递归是有条件的,满足了条件后,才可以递归 。
返回 145
2.7 函数
2.7.5 局部变量和全局变量从程序中各个变量起作用的范围 ( 作用域 ) 来看,变量可以分为局部变量和全局变量 。
1,局部变量在一个函数的内部定义的变量就是内部变量 ( 局部变量 ) 。 如:
float f1(int a)
{int b,c; //a,b,c有效
}
void main( )
{int n,m; //m,n有效
……
}
返回 146
2.7 函数对局部变量作以下几点说明:
( 1)局部变量的作用范围(作用域):只局限在定义它的本函数体之内。
( 2)局部变量的生存期(存在的时间):只有当程序执行到本函数时,才给这些局部变量分配存储单元,当本函数执行完毕后,这些局部变量所占存储单元就被释放。
返回 147
2.7 函数
( 3)不同函数体中可以定义相同名字的变量,但它们代表不同的对象,互不干扰。它们在内存占用不同的内存单元。
( 4) 函数的形式参数也是该函数的局部变量,其他函数不能调用 。
( 5) 在一个函数内部,可以在复合语句中定义变量,但这些变量只在本复合语句中有效,因此,复合语句也可称为,分程序,或,程序块,。
返回 148
2.7 函数
2,静态局部变量 ( 局部静态变量 ),
定义方法是:在函数体内定义变量采用:
static 类型标识符 变量名;
特点:
( 1) 静态局部变量本身也是局部变量,因此其作用域也是局限在定义它的本函数体内,当离开本函数体,该变量就不再起作用,但其值还继续保留 。
( 2) 另一方面,静态局部变量又是静态存储类别的变量,
所以,在整个程序运行开始就被分配固定的存储单元 ( 占用静态存储区 ),整个程序运行期间不再被重新分配,所以其生存期是整个程序运行期间 。
( 3) 静态局部变量的赋初值的时间在编译阶段,并不是每发生一次函数调用就赋一次初值 。 当再次调用该函数时,
静态局部变量保留上次调用函数时的值 。
返回 149
2.7 函数
3,全局变量:
在所有函数体外部定义的变量为外部变量 ( 全局变量 ),全局变量可以被本文件中其他函数所调用 ( 使用 ) 。
全局变量的有效范围为:从定义该变量的位臵开始到本程序文件的结束 。 如:
int p=1,q=5; /*全局变量 */
float f1(int a)
{ int b,c
…… }
char c1,c2; /* 全局变量 */
返回 150
2.7 函数
char f2(int x,int y)
{ int i,j;
…… }
main()
{int m,n.;
……
}
对全局变量的几点说明:
( 1) 全局变量在程序的全部执行过程中都占用固定的内存储单元,而不是仅在需要时才开辟单元,所以其生存期是整个程序运行期间 。
返回 151
2.7 函数
( 2) 全局变量的作用范围是整个程序文件 。 全局变量处于文件的开头定义时,其作用范围为整个文件,否则在定义点之前的函数内使用时,应在函数体内或外部用 extern
说明 。 说明的格式是,extern 类型标识符 变量名;
( 3)在一个程序文件中定义的全局变量,要在同一程序的另外一个程序文件中使用时,应在使用它的程序文件中所有函数体内部或外部对所使用的全局变量用 extern说明。
( 4) 在同一个文件中全局变量与局部变量同名时,则在局部变量的作用范围内,全局变量不起作用 。
4,静态全局变量当在所有函数体的外部用如下格式定义变量时,则这种变量称为静态全局变量 。
static 类型标识符 变量名;
返回 152
2.7 函数静态全局变量的特点是:
( 1) 与全局变量基本相同,只是其作用范围 ( 即作用域 )
是定义它的程序文件,而不是整个程序 。
( 2) 静态全局变量属于静态存储类别的变量,所以它在程序一开始运行时,就被分配固定的存储单元,所以其生存期是整个程序运行期间 。
( 3) 使用静态全局变量的好处是同一程序的两个不同的程序文件中可以使用相同名称的变量名,而互不干扰 。
2.7.6 全局函数和静态函数
1,全局函数凡程序中定义的函数,如果未做特别说明,一律都是全局的 。 也就是说,函数从本质上是全局的,一个程序不管有多少个程序文件所组成,在某个程序文件中可以返回 153
2.7 函数调用同一程序的另外一个程序文件中定义的函数,只要对被调函数的原型进行说明即可 。 声明函数原型的语句:
类型标识符 函数名 ( 形参类型表 ) ;
如:假设程序中定义了 max函数,则:
int max(int,int);就是对函数 max原型的声明 。
2,静态函数:
静态函数定义方法为:
static 类型标识符 函数名 ( 形参及其类型 )
{ 函数体 }
注意,这种函数就只能在定义它的程序文件中调用。
2.7.7 内联函数返回 154
2.7 函数
1,内联函数的定义方法和格式:
inline 函数值的类型 函数名 ( 形参及其类型列表 )
{ 函数体 }
如,inline double square(double x)
{ return x*x; }
void main()
{ double x;
cout<<” input a data” ;
cin>>x;
cout<<” the squre is,<<square(x);
}
返回 155
2.7 函数
2,内联函数与普通函数的区别和联系
( 1) 在定义内联函数时,函数值的类型左面有,inline”
关键字,而普通函数在定义时没有此关键字 。
( 2) 程序中调用内联函数与调用普通函数的方法相同 。
( 3) 当在程序中调用一个内联函数时,是将该函数的代码直接插入到调用点,然后执行该段代码,所以在调用过程中不存在程序流程的跳转和返回问题 。 而普通函数的调用,程序是从主调函数的调用点转去执行被调函数,待被调函数执行完毕后,再返回到主调函数的调用点的下一语句继续执行 。
( 4) 从调用机理看,内联函数可加快程序代码的执行速度和效率,但这是以增加程序代码为代价来求得速度的 。
返回 156
2.7 函数
3,对内联函数的限制应 注意,不是任何一个函数都可定义成内联函数 。
( 1) 内联函数的函数体内不能含有复杂的结构控制语句,
如,switch和 while,如果内联函数的函数体内有这些语句,
则编译将该函数视同普通函数那样产生函数调用代码 。
( 2) 递归函数不能被用来作为内联函数 。
( 3) 内联函数一般适合于只有 1~ 5行语句的小函数,对一个含有很多语句的大函数,没有必要使用内联函数来实现。
返回 157
2.7 函数
2.7.8 函数重载
1,什么是函数重载函数重载是指一个函数可以和同一作用域中的其他函数具有相同的名字,但这些同名函数的参数类型、参数个数、返回值、函数功能可以完全不同。如,
#include <iostream.h>
void whatitis(int i)
{ cout<<"this is integer"<<i<<endl;}
void whatitis(char c[])
{ cout<<“this is string”<<c<<endl; }
main()
{ int i=1;
char c[]="abcdef";
返回 158
2.7 函数
whatitis(i);
whatitis(c);
}
在本例中定义了两个名称都叫 whatitis的函数,但它们的形参类型不同 。 因此,这两个函数就是重载函数 。
2,为什么要使用函数重载在原有 C语言中,每个函数必须有其唯一的名称,这样的缺点是所有具有相同功能,而只是函数参数不一样的函数,就必须用一个不同的名称,而 C++中采用了函数重载后,对于具有同一功能的函数,如果只是由于函数参数类型不一样,则可以定义相同名称的函数 。
3,匹配重载函数的顺序由于重载函数具有相同的函数名,在进行函数调用时,
返回 159
2.7 函数系统一般按照调用函数时的参数个数,类型和顺序来确定被调用的函数 。 具体来说,按以下三个步骤的先后次序找到并调用那个函数:
( 1) 寻找一个严格的匹配,即:调用与实参的数据类型,
个数完全相同的那个函数 。
( 2) 通过内部转换寻求一个匹配,即:通过 ( 1) 的方法没有找到相匹配的函数时,则由 C++系统对实参的数据类型进行内部转换,转换完毕后,如果有匹配的函数存在,则执行该函数 。
( 3) 通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,就调用那个函数 。 即:在函数调用处由程序员对实参进行强制类型转换,以此作为查找相匹配的函数的依据 。 如:
返回 160
2.7 函数
#include <iostream.h>
void print(double d)
{ cout<<"this is a double "<<d<<"\n"; }
void print(int i)
{ cout<<"this is an integer "<<i<<"\n"; }
void main()
{ int x=1,z=10;
float y=1.0;
char c='a';
print(x); //按规则 ( 1) 自动匹配函数 void print(int i)
print(y); //按规则 ( 2) 通过内部转换匹配函数
void print(double i)
返回 161
2.7 函数
//因为系统能自动将 float型转换成 double型
print(c); //按规则 ( 2) 通过内部转换匹配函数
void print(int i)
//因为系统能自动将 char型转换成 int型
print(double(z)); //按规则 ( 3) 匹配 void print(double i)
//因为程序中将实参 z强制转换为 double型 。
}
4,定义重载函数时的 注意事项
( 1) 重载函数间不能只是函数的返回值不同,应至少在如:形参的个数,参数类型或参数顺序上有所不同 。
返回 162
2.7 函数
void myfun(int i)
{ }
int myfun(int i)
{ }
这种重载就是错误的 。
( 2) 应使所有的重载函数的功能相同 。 如果让重载函数完成不同的功能,会破坏程序的可读性 。
返回 163
2.7 函数
2.7.9 默认参数的函数
1,默认参数的函数
C++允许在定义函数时给其中的某个或某些形式参数指定默认值,这样,当发生函数调用时,如果省略了对应位臵上的实参的值时,则在执行被调函数时,以该形参的默认值进行运算 。 如:
#include <iostream.h>
void sum(int num=10) //形参默认值
{ int i,s=0;
for(i=1;i<=num;i++)
s=s+i;
cout<<"sum is "<<s<<"\n"; }
void main()
{ sum(100); //提供了实参值,被调函数以 100进行运算,
输出结果为 5050
sum(); //省略实参值,使用形参默认值 10,输出结
} 果为 55
返回 164
2.7 函数
2,使用默认参数的函数的 注意事项
( 1) 默认参数一般在函数说明中提供 。 如果程序中既有函数的说明又有函数的定义时,则定义函数时不允许再定义参数的默认值 。 如果程序中只有函数的定义,而没有说明函数,则默认参数才可出现在函数定义中 。 如:
void point(int x=10,y=20);
void main()
{ }
void point (int x,int y)
{ cout<<x<<endl;
cout<<y<<endl;
}
返回 165
2.7 函数
( 2) 默认参数的顺序:如果一个函数中有多个默认参数时,则形参分布中,默认参数应从右至左逐渐定义 。 如:
void myfunc(int a=1,float b,long c=20); //错误
void myfunc(int a,float b=2.1,long c=30); //正确返回 166
2.8 指针类型及使用
2.8 指针类型及使用
2.8.1 指针的概念一个变量在内存中所占存储单元的地址号就是该变量的指针 。
如,int i;
i=20;
假设 i变量在内存中所占存储单元的地址号为,1000,此时称 1000这个存储地址为变量 i的指针,而 20是变量 i的值 。
2.8.1.1指针变量的定义专门存放其他变量地址的变量称为 指针变量 。 和其他变量的定义类似,指针变量在使用前也必须定义其类型 。 其定义的一般形式为:
类型标识符号 *指针变量名表如,int i=50;
int *ip;
说明:
( 1) 指针变量名前面的 ‘ *’ 表示该变量为指针变量,它不是变量名本身的一部分 。
( 2) 此处的类型标识符是该指针变量所要指向的变量的类型 。
返回 167
2.8 指针类型及使用
( 3) 变量的指针和指向变量的指针变量的区分:指针是某一变量在内存中所占存储单元的地址,是一个地址值 。
而指针变量则是专门存放其他变量的地址的变量,是个变量,如果某一指针变量中存放了另外一个变量的指针,
则称该指针变量是 指向 那个变量的指针变量 。
2.8.1.2 与指针运算有关系的两个运算符
1,&:求某一变量所占存储单元的存储地址 。
如,int i=50;
int *ip;
ip=&i; //&i—— 求变量 i 的存储单元的地址 ( 即指针 )
此时,指针变量 ip存放了变量 i的存储地址 ( 指针 ),因此称指针变量 ip此时是指向变量 i的 。
返回 168
2.8 指针类型及使用
2,*,取出指针变量所指向的变量的内容,后面跟指针变量 。
如,*ip为取出指针变量所指向的变量的内容 。
即由于 ip是指向变量 i的,所以 *ip 与 i是等价的 。
2.8.1.3 指针变量的引用指针变量的引用,即使用指针变量,其使用方法和普通变量的使用原理一致,但要 注意,
( 1) 指针变量是一个变量:一个指针变量和普通变量一样,在内存中也占存储单元,因此一个指针变量也相当于一个容器,所以指针变量也有其指针,这就是指针变量的指针 。
返回 169
2.8 指针类型及使用
( 2) 指针变量内只能存放其他变量的地址,而不能直接存放一个普通数据 。
( 3) 一个指针变量只能指向同一个类型的变量,如上例中指针变量 ip只能总是指向整型变量 。
( 4) 一个指针变量只有先指向某一个变量后,才可利用该指针变量对它所指向的变量进行操作 ( 间接访问 ) 。
【 例 2-15】 指针变量及其使用方法 。
#include<iostream.h>
void main()
返回 170
2.8 指针类型及使用
{ int a,b;
int *ip1,*ip2; //定义了两个指向整型的指针变量 。
a=100;b=100;
ip1=&a;ip2=&b; //将变量 a,b的地址赋给两个拂针变量,
这时,指针变量 ip1指向变量 a,而 ip2指向 b
cout<<a<< ‘ ’ <<b<<endl;
cout<<*ip1<<‘ ’ <<*ip2<<endl;
//等价于 cout<<a<<‘ ’ <b<<endl;
*ip1=200; //等价于 a=200;
*ip2=300; //等价于 b=300;
cout<<*ip1<<' '<<*ip2<<endl;
}
返回 171
2.8 指针类型及使用
2.8.2 const指针
1,指向常量的指针变量的定义与使用
const 类型标识符 *指针变量名;
如,const int *p;
用这种方法定义的指针变量,借助该指针变量只可读取它所指向的变量或常量的值,但不可借助该指针变量对其所指向的对象的值进行修改(即重新赋值)。但是,
可允许这种指针变量指向另外一个同类型的别的变量。
如:
返回 172
2.8 指针类型及使用
include <iostream.h>
void main()
{ const int i=20;
int k=40;
const int *p; //定义指向常量的指针变量 p
p=&i; //指针变量 p指向变量 i
cout<<*p<<i;
*p=100; //该句错误,不可借助 p对它所指向的目标进行重新赋值
p=&k; //可以使 p指向另外一个同类型的变量
cout<<*p<<k;
*p=200; //该句错误
k=200;}
返回 173
2.8 指针类型及使用
2,指针常量指针常量的定义格式为:
类型标识符 * const 指针变量名 =初始指针值;
如,char * const p=”abcde”
用该种方法定义的指针变量,其值 ( 是一个指针值 ),不可进行修改,但可以借助该指针变量对其所指向的对象的值进行读取或修改 。 另外,这种指针在定义时必须初始化 。 如:
返回 174
2.8 指针类型及使用
void main()
{ char s[]="askdfsljfl";
char * const p=s; //必须初始化
p=,xyz” ; //该句错误,不可再使指针变量指向另外一个地址 ( 指针 )
cout<<*p;
*p=‘ s’ ;
cout<<*p;
p++;
*p=‘ q’ ;
cout<<*p; }
返回 175
2.8 指针类型及使用
3,指向常量的指针常量指向常量的指针常量的定义方法为:
const 类型标识符 * const 指针变量名 =初始指针值;
如,int b;
const int * const p=&b;
用这种方法定义的变量,既不允许修改指针变量的值,也不允许借助该指针变量对其所指向的对象的值进行修改 。 另外,该变量在定义时必须初始化 。 如:
返回 176
2.8 指针类型及使用
void main()
{ int a=10; int c=30;
const int b=20;
const int * const p=&a;
const int * const q=&b;
p=&c; //错误
*p=50; //错误
}
返回 177
2.8 指针类型及使用
2.8.3 指针与函数前面讲过,函数的参数可以为整型,实型,字符型等普通变量 。 实参与形参间参数的传递是单向的,值传递,。
但函数的参数也可为指针,它的作用是将一个变量的地址传给被调函数的形参 。 此时主调函数的调用点上的实参必须是地址值 ( 指针 ),而被调函数的形参一定要定义成指针变量的形式此时,被调函数的形参得到的是实参的指针,因此,该形参变量就指向实参,在被调函数中对形参的操作就相当于对它所指向的实参的操作 。
返回 178
2.8 指针类型及使用
【 例 2-16】 交换两个变量的值。
#include<iostream.h>
void swap(int *p1,int *p2) //形参 p1和 p2的要定义成指针变量形式
{ int p;
p=*p1;
*p1=*p2;
*p2=p; }
void main()
{ int a,b;
cin>>a>>b;
swap(&a,&b); //以变量 a和变量 b的地址作为实参值 。
cout<<a<<','<<b; }
返回 179
2.8 指针类型及使用
2.8.3.1 函数的指针一个函数在内存中的起始地址就是该函数的指针 。
在 C++中,函数的名称就代表了该函数的指针 。
指向函数的指针变量的一般定义形式为,
数据类型标识符 (*指针变量名 )( );
在 C++语言中,指针变量可以指向普通变量,它也可以指向函数 。
返回 180
2.8 指针类型及使用
【 例 2-17】 求 a和 b中较大者。
#include "iostream.h"
int max(int x,int y); //声明被调函数 max
void main()
{ int a,b,c;
cin>>a>>b;
c=max(a,b);
cout<<c; }
int max(int x,int y)
{ int z;
if(x>y)
z=x;
else
z=y;
return(z); }
返回 181
2.8 指针类型及使用如果改用指向函数的指针变量的话,则 main函数为,
void main()
{ int (*p)(); //定义了一个指向返回值为 int型的函数的指针变量 p
int a,b,c;
p=max; //将函数 max的首地址 ( 即指针 ) 赋给指针变量 p
cin>>a>>b;
c=(*p)(a,b);
cout<<c;
}
返回 182
2.8 指针类型及使用说明:
( 1) int (*p)() 说明了一个指向返回值为整型数据的函数的指针 。
( 2) p=max 表示把函数的入口地址赋给指针变量 p,那么 *p
就是函数 max.因此 c=(*p)(a,b);和 c=max(a,b)等价 。
注意,
( 1) 函数的调用可以通过函数名调用,也可通过函数指针调用 。
( 2) int (*p)();只是表示定义了一个指向函数的指针变量 。
( 3) 在函数指针变量赋值时,只须给出函数名,不必给出参数,如,p=max; 因为只是传递函数的地址 。
( 4) 对指向函数的指针做象 p+n,p++,p—等算数运算是无意义的 。
返回 183
2.8 指针类型及使用
2.8.3.2 把指向函数的指针变量作函数参数函数的指针变量主要的用途就是把指针作为参数传递到其它函数 。 如,
sub(int (*x1)(),int (*x2)())
{ int a,b,i,j;
a=(*x1)(i);
b=(*x2)(j); }
返回 184
2.8 指针类型及使用
2.8.3.3 返回指针值的函数返回指针值的函数的定义方式为,
类型标识符号 *函数名 (参数名 )
如,int *a(int x,int y)
{…… }
此时,该函数体内的 return语句的形式为,return(指针值 );
返回 185
【 例 2-18】 定义 findmax()函数,其功能是寻找数组中的最大元素,将该元素的下标通过参数返回,并返回其地址值,编程实现 findmax()函数。
#include "iostream.h"
int *findmax(int *array,int size,int *index);
void main()
{int a[10]={33,91,54,67,82,37,85,63,19,68};
int *maxaddr;
int idx;
maxaddr=findmax(a,sizeof(a)/sizeof(*a),&idx);
cout<<idx<<endl;
cout<<maxaddr<<endl;
cout<<a[idx]<<endl; }
int *findmax(int *array,int size,int *index)
{ int max,i;
max=*(array+0);
for (i=1;i<size;i++)
if (max<*(array+i))
{ max=*(array+i);
*index=i; }
return(array+*index); }
返回 186
2.8 指针类型及使用
2.8.4 指针与数组数组的指针即整个数组在内存中的起始地址;
数组元素的指针是数组中某一元素所占存储单元的地址 。
引用数组元素时是利用数组的下标进行的,也可以利用指针来进行,
利用指针引用某一数组元素时,即可以先使一指针变量指向某一数组元素,然后通过该指针变量对它所指向的数组元素进行操作 。
2.8.4.1 指向数组元素的指针变量的定义与赋值指向数组元素的指针变量的定义与以前定义指针变量的方法相同,只要 注意 指针变量定义时的类型要与所要指向的数组的类型一致即可 。
返回 187
2.8 指针类型及使用如,int a[10];
int *p;
p=&a[0]; //把数组元素 a[0]的地址赋给指针变量 p 。
C++语言中规定:数组名就代表数组首地址 。 也就是数组第 0号元素的地址 。 如:
int a[10];
int *p;
p=&a[0]; /*与 p=a;是等价的 */
p=&a[0];与 p=a;是等价的 。 但要 注意,其作用是把数组
a 的起始地址赋给指针变量 p,而不是把数组 a的各元素的地址赋给 p。
返回 188
2.8 指针类型及使用
2.8.4.2 通过指针变量使用数组元素假设 p为指向某一数组元素的指针变量 。 C++语言规定:
p+1指向数组的下一个元素 。 ( 注意不是单纯的 p加 1) 。
设定义了一个数组 a[10],p的初值为 &a[0],即此时 p指向 a[0]
元素,则:
( 1) p+1 或 a+1就是 a[1]元素的存储地址,即它们都指向数组的第 1号元素 a[1]。 所以 *( p+1) 或 *(a+1)就与 a[1]
是等价的 。
( 2) p+i或 a+i就是 a[i]元素的存储地址,即它们都指向数组的第 i号元素 a[i]。 所以 *(p+i)或 *(a+i)就与 a[i]是等价的 。
因此,利用此方法就可访问到数组元素 。 如:
返回 189
2.8 指针类型及使用
main()
{ int a[0];
int *p,i;
for(i=0;i<10;i++)
cin>>a[i];
p=a;
for (i=0;i<10;i++)
cout<<*(p+i); //等价于 cout<<a[i];
}
返回 190
2.8 指针类型及使用对以上讲过的内容再作几点补充说明:
假设已定义了一个数组 a[10],且定义了一个指针变量 p,赋初值 a.即 p=a;,则:
( 1) p++是指向数组元素的下一个元素;即,a[1]。
( 2) *p++的运算,*p++等同于 *(p++),它的作用是先得到
p所指向的元素的值 ( 即 *p),然后再使 p+1。
如,for(i=0;i<10;i++,p++)
cout<<*p++;
( 3) *(p++) 与 *(++p)的作用是不同的。
*(p++)是先取 p的值作 *运算,然后再使 p加 1( 即指向下一个元素 ) ;
*(++p)是先使 p加 1( 即使 p指向下一个元素 ),然后再作 *运算 。
返回 191
2.8 指针类型及使用如:若 p的初值为 a,(即 &a[0]),输出 *(p++)时,得到 a[0]的值,
而输出 *(++p),则得到 a[1]的值 。
( 4) (*p)++表示 p所指的元素值加 1,对上例来说 a[0]++。
( 5) 对于指针的 --( 自减 ) 运算原理同上 。
( 6) 只有指向数组元素的指针变量才可进行自加或自减运算 。
2.8.4.3 数组名作函数参数数组名可以用来作为实参和形参 。 用数组名作实参,
在调用函数时实际上是把数组的首地址传递给形参,这样,实参数组就与形参数组共占同一段内存,那么形参数组中元素的值发生变化后,实参数组中各元素的值也发生变化,但这种变化并不是从形参传回实参的,而是返回 192
2.8 指针类型及使用由于形参与实参数共享同一段内存而造成的,
利用数组名作为函数的参数时可以用以下四种情况实现,
( 1) 形参和实参都用数组名
( 2) 实参用数组名,形参用指针变量
( 3) 实参和形参都用指针变量
( 4) 实参用指针变量,形参用数组名
【 例 2-19】 函数 func是实现数组排序的过程 。 主函数将 8
个整数读入,调用 func排序并输出结果 。
#include <iostream.h>
void func(int *); //func的函数原型
void main()
返回 193
2.8 指针类型及使用
{ int data[8];
int i;
cout<<"\n输入 8个数,";
for ( i =0; i<8; i++ )
cin>>data[i];
func(data);
cout <<"\n排序输出,";
for ( i =0; i<8; i++ )
cout<<data[i]<<",";
cout <<endl<<endl;
}
返回 194
2.8 指针类型及使用
void func(int *s)
{ int i,j;
int work;
for ( i=0; i<8; i++ )
for ( j=i; j<8; j++ )
if (*(s+i)<*(s+j))
{ work=*(s+i);
*(s+i)=*(s+j);
*(s+j)= work;
}
}
返回 195
2.8 指针类型及使用
2.8.5 指针与字符串
2.8.5.1 字符串的指针和指向符串的指针变量字符串在内存中的首地址称字符串的指针在 c++程序中,可以用两种方法来实现字符串的保存:
( 1) 用字符数组来实现
( 2) 用字符串指针实现如,main()
{ char *string=”languaye”;
cout<<string;
}
输出结果,c language
注意,输出时的指针变量的写法是 string而不是 *string。
返回 196
2.8 指针类型及使用
2.8.5.2 字符串指针作函数参数可以采用以下 4种方法:
实参 形参
( 1) 数组名 数组名
( 2) 数组名 字符指针变量
( 3) 字符指针变量 字符指针变量
( 4) 字符指针变量 数组名
【 例 2-20】 将字符串 a复制为字符串 b。
返回 197
2.8 指针类型及使用
#include<iostream.h>
void copy_string(char *from,char *to)
{ for(;*from!='\0';from++,to++)
*to=*from;
to='\0'; }
void main()
{ char a[20]="c language";
char b[20]="very good";
copy_string(a,b);
cout<<a<<endl;
cout<<b<<endl; }
返回 198
2.8 指针类型及使用
2.8.6 指针数组和指向指针的指针,
1,指针数组如果一个数组中的元素均为指针类型的数据,则称这个数组为指针数组 。 其定义方式为,
类型标识符 * 数组名 [数组长度 ]
如,int *p[4] ;
这种指针数组比较适合于处理字符串 。 如,
char *name[3]={,fortranm”,” basic”,” pascal” };
2,指向指针的指针,
前面已经介绍过指针数组,
返回 199
2.8 指针类型及使用如,char *name[3]
说明该数组中的元素都是指针,数组代表了该指针数组的起始地址,name是指向指针型数据的指针 。
定义指向指针的指针变量的方式为:
类型标识符号 **变量名如,char **p;
**p相当于 *(*p),说明指针变量 p是指向一个字符指针变量 ( 指向字符型数据的指针变量 ) 的 。
返回 200
2.9 引用
2.9.1 引用的概念,声明和使用
1.引用及声明方法引用就是某一变量(目标)的一个别名,这样对引用的操作就是对目标的操作。
引用的声明方法:
类型标识符 &引用名 =目标变量名;
如,int a;
int &ra=a; //定义引用 ra,它是变量 a的引用,即别名说明:
( 1) &在此不是求地址运算,而是起标识作用。
( 2)类型标识符是指目标变量的类型。
( 3)声明引用时,必须同时对其进行初始化。
返回 201
2.9 引用
( 4)引用声明完毕后,相当于目标变量名有两个名称,
即该目标原名称和引用名。
( 5)声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,所以系统并不给引用分配存储单元。
2.引用的使用
( 1)一旦一个引用被声明,则该引用名就只能作为目标变量名的一个别名来使用,所以不能再把该引用名作为其他变量名的别名,任何对该引用的赋值就是该引用对应的目标变量名的赋值。
( 2)对引用求地址,就是对目标变量求地址。
返回 202
2.9 引用
【 例 2-21】 引用的定义及使用方法。
#include <iostream.h>
void main()
{ int a,b=10;
int &ra=a; //定义引用 ra,初始化成变量 a,所以 ra是变量 a的引用(别名)
a=20;
cout<<a<<endl;
cout<<ra<<endl; //等价于 cout<<a<<endl;
cout<<&a<<endl; //输出变量 a所占存储单元的地址
cout<<&ra<<endl; //等价于 cout<<&a<<endl;
返回 203
2.9 引用
ra=b; //等价于 a=b;
cout<<a<<endl;
cout<<ra<<endl; //等价于 cout<<a<<endl;
cout<<b<<endl;
cout<<&a<<endl;
cout<<&ra<<endl; //等价于 cout<<&a<<endl;
cout<<&b<<endl;
}
( 3)由于指针变量也是变量,所以,可以声明一个指针变量的引用。方法是:
类型标识符 *&引用名 =指针变量名;
返回 204
2.9 引用如,#include <iostream.h>
void main()
{
int *a; //定义指针变量 a
int *&p=a; //定义引用 p,初始化为指针变量 a,所以 p是
a的引用(别名)
int b=10;
p=&b; //等价于 a=&b,即将变量 b的地址赋给 a。
cout<<*a<<endl; //输出变量 b的值
cout<<*p<<endl; //等价于 cout<<*a;
}
返回 205
( 4)不能建立数组的引用,因为数组是一个由若干个元素所组成的集合,所以就无法建立一个数组的别名。
( 5)引用是对某一变量或目标对象的引用,它本身不是一种数据类型,因此引用本身不占存储单元,这样,就不能声明引用的引用,也不能定义引用的指针。
如,下例中的操作是达不到的。
int a;
int &ra=a;
int &*p=&ra; //错误
( 6)不能建立空指针的引用,如:不能建立
int &rp=NULL;
2.9 引用返回 206
2.9 引用
( 7)也不能建立空类型 void的引用,如:不能建立
void &ra=3;因为尽管在 C++语言中有 void数据类型,但没有任何一个变量或常量属于 void类型。
2.9.2 用引用作为函数的参数
1.引用作为函数的参数一个函数的参数也可定义成引用的形式,如:我们定义交换两个数的函数 swap,将函数的参数定义成引用的形式:
返回 207
2.9 引用
void swap(int &p1,int &p2) //此处函数的形参 p1,p2都是引用
{ int p;
p=p1;
p1=p2;
p2=p;
}
为在程序中调用该函数,则相应的主调函数的调用点处,
直接以变量作为实参进行调用即可,而不需要实参变量有任何的特殊要求。如:对应上面定义的 swap函数,相应的主调函数可写为:
返回 208
2.9 引用
main()
{ int a,b;
cin>>a>>b; //输入 a,b两变量的值
swap(a,b); //直接以变量 a和 b作为实参调用 swap函数
cout<<a<<‘?<<b; //输出结果 }
上述程序运行时,如果输入数据 10 20并回车后,则输出结果为 20 10。
返回 209
2.9 引用
2.几点说明由上例可看出:
( 1)传递引用给函数与传递指针的效果是一样的,这时,
被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
( 2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,这样形参与形参就占用不同的存储单元,所以形参变量的值是实参变量的副本。因此,当参数传递的数据量较大时,用引用比用一般变量传递参数的效率和所占空间都好。
返回 210
2.9 引用
( 3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中需要重复使用,*
指针变量名,的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。
返回 211
2.9 引用
void swap(int *p1,int *p2)
{ int p;
p=*p1; //必须用,*指针变量名,的形式操作目标数据
*p1=*p2;
*p2=p;
}
main()
{ int a,b;
cin>>a>>b;
swap(&a,&b); //必须以变量 a和 b的地址作为实参
cout<<a<<b;
}
返回 212
2.9.3 如何使一个被调函数同时返回多个值由于函数的返回值是通过函数体中的 return语句完成的,
但一个 return语句只能返回一个值,为此,我们可以采用以下方法:
( 1)利用全局变量的方法:可以在程序的开头定义一些全局变量。这样,当被调函数执行完毕后,所需要的数据已保存在了全局变量中,在主调函数中直接读取全局变量的值即可。
( 2)使用指针或数组的方法:因为在指针作为函数的情况下,可将主调函数的某些变量的地址传递给被调函数。
2.9 引用返回 213
( 3)利用引用的方法:通过前面的学习,我们知道,使用引用传递参数,可以在被调函数中改变主调函数中目标变量的值,这种方法实际上就是可以使被调函数返回多个值。
【 例 2-22】 使用引用使函数返回多个值。以下定义了可以同时返回 10个数中的最大值和最小值的函数 max_min。
2.9 引用返回 214
#include <iostream.h>
void max_min(int *p,int n,int &max,int &min); //声明函数 max_min
void main()
{
int a[10];
int ma,mi;
int i;
for(i=0;i<10;i++)
cin>>a[i];
max_min(a,10,ma,mi); //调用函数 max_min
cout<<ma<<mi;
}
2.9 引用返回 215
2.9 引用
void max_min(int *p,int n,int &max,int &min) //形参 max 和 min定义成引用
{
int i=0;
max=*(p+i);
min=*(p+i);
for(i=1;i<n;i++)
{
if (max<*(p+i))
max=*(p+i); //实质上就是对实参变量 ma赋值
if (min>*(p+i))
min=*(p+i); //实质上就是对实参变量 mi赋值
}
}
返回 216
2.9.4 用引用返回函数值要以引用返回函数值,则函数定义时要按以下格式:
类型标识符 &函数名(形参列表及类型说明)
{函数体 }
说明:
( 1)以引用返回函数值,定义函数时需要在函数名前加 &
( 2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
【 例 2-23】 以下程序中定义了一个普通的函数 fn1(它用返回值的方法返回函数值),另外一个函数 fn2,它以引用的方法返回函数值。
2.9 引用返回 217
#include <iostream.h>
float temp; //定义全局变量 temp
float fn1(float r); //声明函数 fn1
float &fn2(float r); //声明函数 fn2
float fn1(float r) //定义函数 fn1,它以返回值的方法返回函数值
{ temp=(float)(r*r*3.14);
return temp; }
float &fn2(float r) //定义函数 fn2,它以引用方式返回函数值
{temp=(float)(r*r*3.14);
return temp;
}
2.9 引用返回 218
void main() //主函数
{float a=fn1(10.0); //第 1种情况,系统生成要返回值的副本(即临时变量)
float &b=fn1(10.0); //第 2种情况,可能会出错(不同
C++系统有不同规定)
//不能从被调函数中返回一个临时变量或局部变量的引用
float c=fn2(10.0); //第 3种情况,系统不生成返回值的副本
//可以从被调函数中返回一个全局变量的引用
float &d=fn2(10.0); //第 4种情况,系统不生成返回值的副本
//可以从被调函数中返回一个全局变量的引用
cout<<a<<c<<d;}
2.9 引用返回 219
2.9 引用
2.9.5 一个返回引用的函数值作为赋值表达式的左值一般情况下,赋值表达式的左边只能是变量名,即被赋值的对象必须是变量,只有变量才能被赋值,常量或表达式不能被赋值,但如果一个函数的返回值是引用时,
赋值号的左边可以是该函数的调用。
【 例 2-24】 测试用返回引用的函数值作为赋值表达式的左值。
#include <iostream.h>
int &put(int n);
int vals[10];
int error=-1;
void main()
返回 220
2.9 引用
{ put(0)=10; //以 put(0)函数值作为左值,等价于
vals[0]=10;
put(9)=20; //以 put(9)函数值作为左值,等价于
vals[9]=10;
cout<<vals[0];
cout<<vals[9];}
int &put(int n)
{ if (n>=0 && n<=9 )
return vals[n];
else { cout<<”subscript error”;
return error; }
}
返回 221
2.9 引用
2.9.6 用 const限定引用声明方式,const 类型标识符 &引用名 =目标变量名;
用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为 const,达到了引用的安全性。
【 例 2-25】
#include,iostream.h”
double &fn(const double &pd)
{ static double ad=32;
ad+=pd;
cout<<pd<<endl;
return ad;
}
返回 222
2.9 引用
#include,iostream.h”
double &fn(const double &pd)
{ static double ad=32;
ad+=pd;
cout<<pd<<endl;
return ad;
}
void main()
{ double a=100.0;
double &pa=fn(a);
cout<<pa<<endl;
a=200.0;
pa=fn(a);
cout<<pa<<endl;
}
程序运行的结果为,100
132
200
332
返回 223
2.9 引用
2.9.7 引用总结
( 1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大对象的传递效率和空间不如意的问题。
( 2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过 const的使用,保证了引用传递的安全性。
( 3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作,程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,
对引用的操作就是对目标变量的操作。
返回 224
2.10 结构体、共用体和枚举
2.10.1 结构体数组中的各元素是属于同一类型的,但有时需要将不同类型的数据组合成一个有机的整体,并且这些数据是相互联系的,这就引出了结构体 。 结构体是由多种类型的数据组成的整体 。 组成结构体的各个分量称为结构体的数据成员 ( 简称成员 ) 。
2.10.1.1 定义结构体定义结构体的一般格式为:
struct 结构体名
{
成员列表
}变量名列表;
返回 225
2.10 结构体、共用体和枚举结构体定义是以关键字 struct开始的,结构体名应是有效的 C++标识符。结构体中的每个成员都必须通过定义来确定成员名及其类型。例如:
struct student
{ int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
}student1;
其中,student是定义的结构体名,该结构体有四个成员变量 num,name,sex,age。 student1是定义的结构体变量。
返回 226
2.10 结构体、共用体和枚举也可以在结构体定义后再定义结构体变量。格式是:
struct 结构体名 变量名列表;
如:
struct student
{
int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
};
struct student student1;
student student1;
返回 227
2.10 结构体、共用体和枚举
2.10.1.2 结构体变量的初始化结构体变量的初始化就是在定义结构体变量的同时,
为其成员提供初值,可采用以下两种方法:
( 1)在定义结构体类型的同时,为结构体变量初始化。
struct 结构体名
{ 成员列表
}变量名 ={初始值列表 };
如,struct student
{int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
}student1={9901,"wang",?f?,23};
返回 228
2.10 结构体、共用体和枚举
( 2)利用已有的结构体类型定义结构体变量,并同时初始化。格式是:
结构体名称 变量名 ={值 1,值 2, };
如,student stu={1,”zhang”,?M?,20,90.0};
此时,student1变量中的 num成员的值为 9901,name成员的值为 "wang",sex成员的值为 23。
2.10.1.3 结构体变量的引用定义了结构体变量以后,就可以在程序中使用这些变量 。 引用结构体变量时应 注意,
( 1) 不能将结构体变量作为一个整体来引用,只能引用结构体变量中的成员 。 引用结构体变量中成员的格式为:
结构体变量名,成员名返回 229
2.10 结构体、共用体和枚举如,cout<<student1.name;
此处的,,” 是成员运算符,它的优先级别最高 。
( 2) 若结构体的成员本身又是一个结构体变量,则要使用多个成员运算符,一级一级地找到最低一级的成员进行引用 。
( 3) 对结构体成员变量的使用可像普通那样进行,如:
进行赋值,参加运算等 。 如:
struct student s1,s2;
s1.num=9901;
s2.num=s1.num+1;
返回 230
2.10 结构体、共用体和枚举
( 4) 可以将一个已有值的结构体变量的值直接赋给另外一个相同类型的结构体变量 。 方法是:
结构体变量名 1=结构体变量名 2;
如,student st1={1,”zhang”,?M?,20,90.0};
student st2; st2=st1;
( 5) 可以应用成员的地址 。 也可以引用结构体变量的地址 。 如:
&student.num &st1
返回 231
2.10 结构体、共用体和枚举
2.10.1.4 结构数组结构数组:即数据类型为结构体类型的数组,这样,
数组中的每个元素都属于同一种结构体类型,每一元素都分别包含了结构体中的每个成员 。
1,结构数组的定义
Struct student
{int num;
char name[20];
int age;
float score;
char addr[30];};
student stu[3];
返回 232
2.10 结构体、共用体和枚举这就定义了一个结构数组 stu,它已含三个元素,其中每个元素都为 student类型,且每个数组元素都各自拥有自己的一套结构成员 num,name,age,score和 addr。
2,结构体数组的初始化结构体数组在定义时也可以进行初始化 。 其初始化方法与一般数组的初始化方法基本相同,只是必须为每个元素提供各结构成员的值,如:
struct student
{ int num;
char name[20];
char sex;
返回 233
2.10 结构体、共用体和枚举
int age;
};
student stu[3]={{1,"sum1",?M?,20},
{2,"zhao2",?M?,25},
{3,"qian3",?M?,21}};
2.10.1.5指向结构体类型的指针
1,指向结构体变量的指针结构体变量的指针:是指结构体变量所占内存单元的起始地址 。 因此,可以定义指针变量指向结构体变量 。
此时该指针变量的值就是结构体变量在内存中起始地址 。
【 例 2-26】 指向结构体变量的指针的使用。
返回 234
2.10 结构体、共用体和枚举
#include "iostream.h"
#include "string.h"
void main()
{ struct student //定义结构体类型 student
{long int num;
char name[20];
char sex;
float score;};
student stu1; //定义结构体类型 student的变量 stu1
student *p; //定义 student类型的指针变量 p
p=&stu1; //将结构体变量 stu1的地址赋给指针变量 p
stu1.num=1; //分别给结构体变量 stu1的 num,name、
sex,score成员赋值返回 235
2.10 结构体、共用体和枚举
strcpy(stu1.name,"li lin");
stu1.sex='M';
stu1.score=89;
//输出 stu1各成员的值
cout<<stu1.num<<"\t"<<stu1.name<<"\t"<<stu1.sex<<"\t"
<<stu1.score<<endl;
//借助指针变量 p输出它所指向的结构体变量各成员的值
cout<<(*p).num<<"\t"<<(*p).name<<"\t"<<(*p).sex<<"\t"
<<(*p).score<<endl;
cout<<p->num<<"\t" << p->name<<"\t" << p->sex<<"\t" << p-
>score<<endl;
}
返回 236
2.10 结构体、共用体和枚举程序的运行结果:
1 li lin M 89
1 li lin M 89
1 li lin M 89
可见,三种访问结构体变量各成员的值的结果完全相同 。
程序说明:
( 1) 上例中 (*p).num也可写为 p->num。
( 2) 结构体取成员的运算可以采用以下三种形式:
① 结构体变量名,成员名
② ( *结构体指针变量名 ),成员名
③ 结构体指针变量名 ->成员名
2,指向结构体数组的指针返回 237
2.10 结构体、共用体和枚举
【 例 2-27】 指向结构体数组的指针的使用 。
#include <iostream.h>
struct student
{ int num;
char name [20];
char sex;
int age ;
};
Student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
void main()
返回 238
2.10 结构体、共用体和枚举
{student *p;
for (p=stu;p<stu+3;p++)
cout<<p->num<<"\t"<<p->name<<"\t"<<p->sex<<"\t"<<p-
>age<<endl;
}
程序的输出结果为:
1 li lin M 18
2 sum M 19
3 zhao M 20
把 stu赋给指针变量 p,就表示 p指向了该数组的起始地址 。 p++ 表示 p指向数组的下一个元素,利用这种方法可以访问数组中所有元素的值 。
返回 239
2.10 结构体、共用体和枚举
2.10.1.6 用结构体类型作为函数的参数
1,用结构体类型的变量作函数的参数 (传值 )
在 C++语言中,允许把结构体类型的变量直接作为函数的参数,但要 注意,此时主调函数的调用点上的实参与被调函数相应位臵上的形参必须是相同的结构体类型,是将实参的值 ( 各成员的值 ) 传递给相应的形参 。
【 例 2-28】 用结构体类型的变量作为函数的参数 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
返回 240
2.10 结构体、共用体和枚举
int age ;};
void print(student);
Student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
void main()
{ int i;
for (i=0;i<3;i++)
print(stu[i]);
}
void print(student s)
{ cout<<s.num<<"\t"<<s.name<<"\t"<<s.sex<<"\t"<<s.age<<
"\t"<<endl;}
返回 241
2.10 结构体、共用体和枚举程序的执行结果是:
1 li lin M 18
2 sum M 19
3 zhao M 20
可见,当把一个结构体类型的变量作为函数的参数时,
可以将该变量的值 ( 包含结构体类型中各成员的值 ) 传递给被调函数的形参 。
2,用指向结构体的指针作函数的参数 ( 传指针 )
用指向结构体变量的指针作参数 。 这种方式同指针作为函数的参数的原理一致,传递的是结构体变量的地址 ( 指针 ) 。
返回 242
2.10 结构体、共用体和枚举
【 例 2-29】 用指针的方法实现例 2-28 程序的功能 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
void print(student *);
Student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
返回 243
2.10 结构体、共用体和枚举
void main()
{ int i;
for (i=0;i<3;i++)
print(&stu[i]);}
void print(student *s)
{cout<<s->num<<"\t"<<s->name<<"\t"<<s->sex<<"\t"<<
s->age<<"\t"<<endl;}
3,用结构体变量的引用作为函数的参数此时,被调函数的形参必须声明成引用形式,函数的形参作为实参的一个别名来使用,从而达到对实参操作的目的 。
返回 244
2.10 结构体、共用体和枚举
【 例 2-30】 用结构体变量引用的方法实现例 2-28程序的功能 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
void print(student &);
student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
返回 245
2.10 结构体、共用体和枚举
void main()
{ int i;
for (i=0;i<3;i++)
print(stu[i]);
}
void print(student &s)
{ cout<<s.num<<"\t"<<s.name<<"\t"<<s.sex<<"\t"<<s.age<<
"\t"<<endl;}
2.10.1.7 返回结构体类型的函数
1,返回结构类型值的函数的定义其定义格式如下:
返回 246
2.10 结构体、共用体和枚举结构体名称 函数名 ( 形参及类型说明 )
{ 函数体 }
【 例 2-31】 定义一个返回结构体类型的函数,求所有同学中年龄最大的同学 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
student max(student *,int);
返回 247
2.10 结构体、共用体和枚举
Studentstu[3]={{1,"lilin",'M',18},{2,"sum",'M',19},{3,"zhao",'M',20}};
void main()
{ student maxold;
maxold=max(stu,3);
cout<<maxold.num<<"\t"<<maxold.name<<"\t"<<maxold.age<<endl; }
student max(student *s,int n)
{ int i,age1,index;
age1=s->age;
index=0;
for (i=0;i<n;i++)
if (age1<(s+i)->age)
{ index=i;
age1=(s+i)->age; }
return (*(s+index));
}
返回 248
2.10 结构体、共用体和枚举
2,返回结构的引用的函数与返回其它类型引用的函数的定义方法和原理一致,
但注意不要返回一个局部变量的引用就可 。
2.10.1.8 结构的嵌套
C++语言中,允许定义一个结构体类型,该结构类型中可以包含另外一种结构类型的成员 。 如下例中定义了一个
birthday结构体类型,它含有 year,month,day三个成员;
又定义了第二个结构体类型 student,它含有 num,sex和
birth三个成员,其中 birth成员是 birthday结构体类型 。
struct birthday{int year;int month;int day;};
struct student
{int num;
char sex;
返回 249
2.10 结构体、共用体和枚举
birthday birth; };
student stu; //定义 student结构体类型的变量 stu
此时要访问 stu的 birth成员的值时,要注意使用多个,,”
操作符 。 如,stu.birth.year=1980;
注意,C++语言中,不能定义一个结构体类型,该结构类型中包含自身结构类型的成员 。 但可包含指向自身结构类型的指针 。 如:
可定义,struct student {int num;char name[20];float score;
student *next;};
不可定义,struct student {int num;char name[20];float score;
student next;};
返回 250
2.10 结构体、共用体和枚举
2.10.2 堆内存的分配和释放堆内存就是在程序的运行过程中根据需要而动态分配的一块内存,因此这种内存分配方式是动态分配,而不是静态分配 ( 如:数组 ) 。
2.10.2.1 申请分配内存的方式从内存中申请分配内存的方法有以下两种:
( 1) 利用 malloc函数格式是,void * malloc(字节数 )
该函数如分配内存成功,则返回其起始地址,否则返回 NULL。当程序中使用 malloc函数动态分配内存时,应该在程序的头部嵌入相应的头文件,#include <stdlib.h>
返回 251
2.10 结构体、共用体和枚举如,int *p;
p=(int *)malloc(sizeof(int));
student *ps;
ps=(student *)malloc(sizeof(student));
( 2) 利用 new运算符:
格式 1:指针变量名 =new 类型标识符;
格式 2:指针变量名 =new 类型标识符 ( 初始值 ) ;
格式 3:指针变量名 =new 类型标识符 [内存单元个数 ];
功能:如果分配内存成功,则返回其起始地址,否则返回 0
注意,格式 1和格式 2都是申请分配某一数据类型所占字节数的内存空间;但是在内存分配成功后,同时将一初值存放到该内存单元中;而格式 3可同时分配若干个内存单元,
相当于形成一个动态数组。
返回 252
2.10 结构体、共用体和枚举如,int *p,*q;
student *r;
p=new int; //申请分配 1个 int类型的内存空间 ( 4个字节 )
p=new int(10); //申请 1个 int类型的内存空间,同时将该内存单元中放臵值 10
q=new int[100]; //申请分配 100个 int类型的内存空间 (200B)
r=new student; //申请分配 1个 student类型的内存空间
( sizeof(student)个字节 )
两种方法的区别:使用 malloc函数分配内存时,其返回值要经过类型转换后才可赋给一个指针变量,而利用
new分配内存时则不需要类型转换 。
返回 253
2.10 结构体、共用体和枚举
2.10.2.2 释放内存的方式在 C++语言中,当不再使用动态分配的内存空间时,
可以将这部分内存释放,以方便其他程序代码使用 。
( 1) 利用 free函数 。
格式,free(起始内存地址 );
使用时应嵌入相应的头文件,#include <stdlib.h>
( 2) 利用 delete运算符:
格式 1,delete 指针变量名;
格式 2,delete [ ] 指针变量名;
说明:格式 1可释放某一个内存单元;而格式 2可释放若干个内存单元的空间。如:
#include <iostream.h>
#include <stdlib.h>
返回 254
2.10 结构体、共用体和枚举
void main()
{ int *number,*p,*q;
number=new int[100]; //申请分配 100个 int类型所占内存空间
p=new int; //申请分配一个 int类型所占内存空间 ( 2个字节 )
q=(int *)malloc(10*sizeof(int)); //申请分配 10个 int类型所占内存空间
if (number==NULL || p==NULL || q==NULL)
cout<<"内存分配失败 "<<endl;
else
cout<<"内存分配成功 "<<endl;
//程序的其它部分
delete []number; //释放 number所指向的所有内存空间
delete p; //释放 p所指向的所有内存空间
free (q); //释放 q所指向的所有内存空间
}
返回 255
2.10 结构体、共用体和枚举
2.10.3 共用体类型
1,共用体概念有时需要使几中不同类型的变量放到同一段内存单元中,如:把一个 int型变量,char 型变量,float型变量放于同一地址开始的内存单元中,这三个变量在内存中占的字节数不同,但都从同一地址开始存放,也就是使用覆盖技术,几个变量相互覆盖,这种使几个不同的变量共一段内存的结构称为共用体类型的结构也叫联合 。
2,共用体类型的定义其定义格式为:
union 共用体名
{成员表 } 变量表;
返回 256
2.10 结构体、共用体和枚举如,union data {int i;
char ch;
float f;
}a,b,c;
这表示定义了共用体类型 data,并同时定义了属于该种数据类型的变量 a,b,c。
由此可见:其定义方式与结构的定义方式类似,但二者的含义不同,结构体变量所占内存空间的大小,是各成员所占的内存之和,每个成员分别占有自己的内存单元,而共用体变量所占的内存空间大小于等于占用内存空间最大的成员的长度,如上面定义的 a,b,c三个共用体变量分别占 4个字节 。
返回 257
2.10 结构体、共用体和枚举
3,共用体变量的定义
( 1) 方法 1:在定义共用体类型的同时定义该种类型的变量,如上例中的变量 a,b,c就是在定义 union data类型的同时定义的共用体变量 。
( 2) 方法 2:可以用已定义过的共用体数据类型,定义共用体变量 。 格式是,union 共用体名称 变量名表;
如,union data mydata;
4,共用体变量的引用共用体变量的使用方法基本同结构体变量的使用方法,
并同时 注意 以下原则:
( 1) 不能直接使用共用体变量,而只能使用共用体变量的成员,共用体变量取成员的运算符同结构体变量取成员的运算符,即用,,” 。
返回 258
2.10 结构体、共用体和枚举如:对于上例定义的共用体变量 a来说,可用以下方法引用其中的成员:
a.i 引用共用体变量 a中的整型变量 i
a.ch 引用共用体变量 a中的整型变量 ch
a.f 引用共用体变量 a中的整型边量 f
( 2) 共用体类型的特点:共用体类型可以使用覆盖技术使几个不同类型的变量 ( 成员 ) 共同占用和使用一块内存空间,所以,在每一瞬时只有一个成员起作用,其他的成员不起作用 。
( 3) 共用体变量中当前正在起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用,如:
返回 259
2.10 结构体、共用体和枚举
a.i=1;
a.ch=‘ a?;
a.f=1.5;
在完成以上三个赋值语句后,只有 a.f有效 。
( 4) 共用体变量的地址和各成员的地址都是同一地址 。
如,a&a &a.i,&a.f同一地址值 。
2.10.4 枚举类型
1,枚举类型及其定义方法如果一个变量只有几种可能的取值时,就可以把它定义为枚举类型,所谓枚举就是指将某一变量所有可能的取值一一列举出来 。 枚举类型的定义格式是:
enum 枚举类型名 {枚举元素表 }枚举变量名;
返回 260
2.10 结构体、共用体和枚举如,enum weekday{sun,mon,tue,wed,thu,fri,sat} workday;
这表示定义了枚举类型 weekday,并同时定义了属于该种类型的变量 workday,该变量的取值范围为 sun~sat。 其中
sun~sat称为枚举元素,是 weekday枚举类型变量的所有可能取值 。
2,枚举变量的定义
( 1) 方法 1:在定义枚举类型的同时定义该种类型的变量,
如上例中的变量 workday就是在定义 enum weekday类型的同时定义的枚举变量 。
( 2) 方法 2:可以用已定义过的枚举数据类型,定义枚举变量 。 格式是:
enum 枚举名称 变量名表;
如:可以利用已有的枚举类型 weekday定义变量 enum
weekday myworkday;
返回 261
2.10 结构体、共用体和枚举
3,枚举变量的使用方法
( 1) 由于枚举类型中列出了该种类型变量的所有可能取值,所以可以将某一枚举元素赋给该种类型的变量,
如,workday=mon;是可以的 。
( 2) 在 c++中,对枚举元素作常量处理,所以枚举元素不是变量,不能对它们赋值,如,sun=0; mon=1;不对 。
( 3) 枚举元素作为常量,它们是有值的,C++语言编译系统按定义时的顺序使它们的值为 0,1,2……
如,enum weekday{sun,mon,tue,wen,thu,fri,sat}workday;
中,枚举元素 sun的值为 0,mon元素的值为 1, 。
如果有赋值语句 workday=thu;则说明变量 workday的值为 4。
返回 262
2.10 结构体、共用体和枚举
( 4)当需要改变枚举元素的默认值时,可以在定义枚举类型的同时在枚举元素的后面用,枚举元素 =值,的格式改变,
如,enum weekday {sun=7,mon=1,tue,wed,thu,fri,sat};
2.10.5 类型定义 typedef的使用在 C++语言中,除了可以直接用 C++提供的标准类型名
int,char,floot,double,long去定义类型外,还可以用 typedef定义新的类型名代替已有的类型名 。 如,
Typedef int INTEGER;//为 int类型定义一个新的名称 INTEGER
typedef float REAL; //为 float类型定义一个新的名称 REAL
INTEGER a,b; //定义变量 a,b为 int类型,等价于 int a,b;
REAL c; //定义变量 c为 float类型,等价于 float c;
返回 263
2.10 结构体、共用体和枚举又如,
typedef struct student
{int num;
char name[10];
int score;
}STUDENT; //为结构体类型 struct student定义新的名称 STUDENT
STUDENT a,b; // 定义 a,b为 struct student类型,等价于 struct student a,b;
注意,
( 1) 类型定义名一般用大写 。
( 2) 类型定义只是给已经存在的数据类型增加一个类型名,而没有创造一个新的数据类型 。
返回 264
2.10 结构体、共用体和枚举
2.10.6 编译预处理在 C++程序的源代码中可以使用各种编译指令,这些指令称为编译预处理命令 。 C++提供的预处理命令主要有以下三种:
宏定义命令
文件包含命令
条件编译命令这些命令在程序中都是以,#” 来引导,每条预处理命令必须单独占用一行;它们不是 C++的语句,因此在结尾没有分号,;,。
1,宏定义命令返回 265
2.10 结构体、共用体和枚举宏定义的一般形式为:
#define 宏名 字符串其中,define是宏替换的关键字,,宏名,是需要替换的标识符,,字符串,是被指定用来替换的字符序列 。
如,#define PI 3.1415926
说明:
( 1) #define,宏名和字符串之间一定要有空格 。
( 2) 宏名一般用大写字母表示,以区别于普通标识符 。
( 3) 宏被定义以后,一般不能再重新定义 。 但可以用
#undef来终止宏定义 。
( 4) 一个定义过的宏名可以用来定义其他新的宏,但要注意其中的括号 。 如:
返回 266
2.10 结构体、共用体和枚举
#define A 20
#define B (A+10)
( 5) 还可以有带参数的宏替换 。 如:
#define MAX(a,b) ((a)>(b)?(a):(b))
2,文件包含命令所谓,文件包含,是指将另一个源文件的内容合并到当前程序中 。 C++中,文件包含命令的一般形式为:
#include<文件名 > 或 #include”文件名,
文件名一般是以,h为扩展名,因而称它为,头文件,,
文件包含的两种格式区别在于:将文件名用,< >” 括起来,用来包含那些由系统提供的并放在指定子目录中头返回 267
2.10 结构体、共用体和枚举文件;将文件名用双引号括起来的,用来包含用户自己定义的放在当前目录或其他目录下的头文件或其他源文件 。
文件包含可以将头文件中的内容直接引入,而不必再重复定义,减少了重复劳动,节省了编程时间 。
注意,一条 #include命令只能包含一个文件,若想包含多个文件,则应使用多条包含命令 。
3,条件编译命令在一般情况下,源程序中的所有语句都会参加编译,
但是有时候会希望根据一定的条件编译源文件的部分语句,这就是,条件编译,。 条件编译使得同一源程序在不同的编译条件下得到不同的目标代码 。
在 C++中,常用的条件编译命令有如下三种:
返回 268
2.10 结构体、共用体和枚举
( 1) #ifdef 标识符程序段 1
#else
程序段 2
#endif
该条件编译命令的功能是:如果在程序中定义了指定的,标识符,时,就用程序段 1参与编译,否则,用程序段 2参与编译 。
( 2) #ifndef 标识符程序段 1
#else
程序段 2
#endif
返回 269
2.10 结构体、共用体和枚举该条件编译命令的功能是:如果在程序中未定义指定的,标识符,时,就用程序段 1参与编译,否则,用程序段 2参与编译 。
( 3) #if 常量表达式 1
程序段 1
#elif常量表达式 2
程序段 2
#elif常量表达式 n
程序段 n
#else
程序段 n+1
#endif
返回 270
2.10 结构体、共用体和枚举该条件编译命令的功能是:依次计算常量表达式的值,
当表达式的值为真时,则用相应的程序段参与编译,如果全部表达式的值都为假,则用 else后的程序段参与编译 。
2.10.7 文件及其操作文件是指存储在存储介质上的数据的集合 。 C++将文件看作是由一个一个字符 ( 字节 ) 的数据顺序组成的 。 它的组成形式可以分为,ASCII文件和二进制文件 。 ASCII
文件又称文本文件,它的每一个字节存放一个 ASCII代码,
代表一个字符;二进制文件是将数据用二进制形式存放在文件中,它保持了数据在内存中存放的原有格式 。
无论是文本文件还是二进制文件,都需要用,文件指针,
来操纵。一个文件指针总是和一个文件相关联,当文件每一次打开时,文件指针指向文件的开始,随着对文件的操作,文件指针不断地在文件中移动,并一直指向最返回 271
2.10 结构体、共用体和枚举后处理的字符 ( 字节 ) 位臵 。
对文件的操作有两种方式:顺序文件操作和随机文件操作 。
2.10.7.1 顺序文件操作顺序文件操作,即从文件的第一个字符 ( 字节 ) 开始,
顺序地处理到文件的最后一个字符 ( 字节 ),文件指针相应地从文件的开始位臵到文件的结尾 。
顺序文件操作包括打开文件,读写文件和关闭文件三个步骤 。
文件的打开和关闭是通过使用 fstream类的成员函数 open
和 close来实现的 。 fstream类是用来对文件流进行操作,
它和前面的标准输出输入流 ( cout,cin) 一起,是 C++实现流操作的最基本的类,而且它们有一个共同的基类 ios。
为了能使用这些类的相关函数,还必须在程序中添上相返回 272
2.10 结构体、共用体和枚举关的包含文件,例如,cout和 cin的头文件是 iostream.h,
而 fstream类的头文件是 fstream.h。
1,打开文件打开文件应使用成员函数 open( ),该成员函数的函数原型为:
void open(const unsigned char *filename,int mode,int
access=filebuf::openprot);
其中,filename是一个字符型指针,指定要打开的文件名; mode指定文件的打开方式,其值如表 2.13所示;
access指定了文件的系统属性,其取值为:
0 一般文件 2 隐藏文件
1 只读文件 3 系统文件表 2.13 在 ios类中定义的文件打开方式返回 273
2.10 结构体、共用体和枚举文件打开方式 含 义
in 以输入 ( 读 ) 方式打开文件
out 以输出 ( 写 ) 方式打开文件
app 打开一个文件使新的内容始终添加在文件的末尾
ate 文件打开时,文件指针位于文件尾
trune 若文件存在,则清除文件所有内容;否则,创建新文件
binary 以二进制方式打开文件,缺省时以文本方式打开文件
nocreat 打开一个已有文件,若该文件不存在,则打开失败
noreplace 若打开的文件已经存在,则打开失败
ios::in|ios::out 以读 /写方式打开文件
ios::in|ios::binary 以二进制读方式打开文件
ios::out|ios::binary 以二进制写方式打开文件表 2.13 在 ios类中定义的文件打开方式返回 274
2.10 结构体、共用体和枚举
2,关闭文件在文件操作结束时,应及时调用成员函数 close()来关闭文件 。 如要关闭的文件名为 myfile,则可使用如下语句关闭文件:
myfile.close();
3,文件的读写在打开文件后,就可以对文件进行读写操作了 。
【 例 2-32】 向文本文件中分别写入一个整数,一个浮点数和一个字符串,并读出其中的信息 。
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
返回 275
2.10 结构体、共用体和枚举
void main()
{ fstream myfile;
myfile.open("f1.txt",ios::out); //以写方式打开文件 f1.txt
if(!myfile)
{ cout<<"Can't open file!!"<<endl;
abort(); //退出程序,包含在 stdlib.h中
}
myfile<<20<<endl;
myfile<<4.58<<endl;
myfile<<"Hello World!"<<endl;
myfile.close();
}
返回 276
2.10 结构体、共用体和枚举
2.10.7.2 随机文件操作随机文件操作,即在文件中通过 C++相关的函数移动文件指针,并指向所要处理的字符 ( 字节 ) 。 随机文件提供在文件中来回移动文件指针和非顺序地读写文件的能力,这样在读写文件中的某一数据之前不需要再读写其前面的数据,从而能快速地检索,修改和删除文件中的信息 。
在 istream类中提供了 3个操作读指针的成员函数:
istream&istream::seekg (long pos);
istream&istream::seekg(long off,dir);
streampos istream::tellg();
其中,pos为文件指针的绝对位臵; off为文件指针的相对偏移量; dir为文件指针的参照位臵,其可能值为:
返回 277
2.10 结构体、共用体和枚举
cur=1 文件指针的当前位臵
beg=0 文件开头
end=2 文件尾
tellg()函数没有参数,它返回一个 long型值,用来表示从文件开始处到当前指针位臵之间的字节数 。
在 ostream类中同样提供了 3个操作写指针的成员函数:
ostream&istream::seekp (long pos);
ostream&istream::seekp(long off,dir);
streampos istream::tellp();
这 3个成员函数的含义与前面 3个操作读指针的成员函数相同,只不过它们是用来操作写指针的 。
返回 278
本章小结本章是 C++语言的基础,内容与 C语言多数一致 。
C++语言支持面向对象的程序设计 ( OOP),在面向对象的程序设计中,以,对象,为中心,并且将对象的属性和方法二者封装在一起,这种结合自然地反映了应用领域的模块性,因此具有相对稳定性 。 同时 OOP又引入了,类,( class) 的概念 。 类与类以层次结构组织,
属于某个类的对象除具有该类所描述的特性外,还继承了层次结构中该类上层所有类描述的全部性质,OOP方法的模块性与继承性,保证了新的应用程序设计可在原有对象的数据类型和功能的基础上,通过重用,扩展和细化来进行,而不必从头做起或复制原有代码,这样,
大大减少了重新编写新代码的工作量,同时降低了程序设计过程中出错的可能性,达到了事半功倍的效果 。
返回 279
本章小结一个 C++的程序是由函数构成的,程序中有且仅有一个 main函数,它总是从主函数 main开始运行 。 每个 C++的源程序要以,CPP作为程序存盘时的文件名后缀,源程序需要经过 C++编译系统的编译和连接,最后才能产生可运行的,EXE程序文件 。 C++源程序数据的输入和输出通常利用输入 /输出流对象 cin和 cout来完成,这时要求在程序的开头需要嵌入头文件 iostream.h。
程序的核心任务是对数据进行加工和处理,在 C++中任何数据是有类型的,不同的数据类型的关键字不同,
所占存储单元的大小不同,因而表示数的范围大小也不同 。 另外,根据数据在程序运行过程中是否发生变化将数据分为常量和变量,常量的值固定不变且数据类型是由用户在程序中的书写格式来决定,而变量则必须在程返回 280
本章小结中进行明确的定义,即定义其名称和类型,在程序中,
任何变量都要遵循先定义后使用的规则 。
C++为每种运算符规定了一个运算的优先级和结合特性,以控制各种运算的顺序,利用圆括号可以改变表达式的运算顺序 。 当在表达式中进行运算的数据类型不同时,C++将自动进行隐式转换,当然,用户也可利用强制类型转换的方法进行转换 。
利用程序的三种结构即:顺序结构,选择结构和循环结构可以实现对程序执行流程的控制 。 选择结构可使程序根据某个 ( 些 ) 条件是否成立,从而有选择的执行程序中的程序段,这可以利用 if语句实现 。 而循环结构可使某一段程序有条件地重复执行有限次,可利用 while,do-
while和 for语句实现,并且这些语句可以通过改变条件的形式进行相互转化 。
返回 281
本章小结数组是一个由若干相同类型的变量组成的集合,数组中特定的元素通过下标来访问,同一个数组中所有元素所占存储单元是连续的,整个数组所占存储单元的首地址就是数组中的第一个元素的地址,数组名本身代表了数组的首地址 。 当数组用于存放字符串时,由于字符串具有结束标记 ‘ \0?,所以在定义字符数组的大小时,要多定义一个元素 。
指针就是某一存储单元的地址,指针变量是专门存放其他变量指针的变量,当指针变量中存放了某一变量的地址时,则称该变量指向那个变量 。 因此,指针变量可以指向变量,数组,函数,字符串,结构体等 。 指针还可以作为函数的参数,以传递实参的地址 。
当程序代码量较大时,可根据功能的不同分成更小、
更容易管理的模块,这种模块就是函数。程序中所用的返回 282
本章小结函数有两类,一类是库函数,另一类是用户自定义函数,
库函数可直接使用,而用户自定义函数要先定义后使用 。
一个函数可定义成有参函数,也可定义成无参函数,当函数无返回值时,要把函数的类型定义成 void。 定义函数时,
函数名称后面括号内的参数是形式参数,形式参数可以是普通变量,数组名,指针变量,引用等 。 当发生函数调用时,实参与形参间发生了数据传递,要注意传值与传地址间的区别 。
内联函数是为了提高编程的效率而实现的,它适用于函数体代码较少且程序中不含有复杂程序结构的情况 。 函数重载允许用同一个函数名定义多个函数,系统会根据传递给函数的参数的数目,类型和顺序调用相匹配的函数,
函数重载使程序设计简单化 。
在函数定义中通过赋值运算可指定参数的默认值 。
返回 283
本章小结引用是 C++语言独有的特性,引用就是某一变量的别名,在定义时必须初始化,使用引用的主要目的是在函数参数传递过程中解决大对象的传递效率和空间不如意的问题。当利用引用作为函数的参数时,参数的传递过程中不产生值的副本。不允许声明引用数组,但可以用常量来初始化引用声明。当一个函数返回引用时,要注意局部对象返回的危险。
结构体是一种将不同数据类型的成员组织到一起的构造数据类型,因此,当定义结构体时,不产生内存的分配,
只有在定义了结构体的变量时,才分配内存单元 。 当结构体作为函数的参数进行传递时,其值进行了复制,因此,
当结构体很大时,宜采用结构体的引用传递函数参数 。 在使用结构体变量时,不能直接把它当成一个整体去使用,
返回 284
本章小结而只能访问和使用结构体中的成员 。 结构体取成员的方法是,结构体变量名,成员名,。 另外,在程序中可以定义结构体数组,也可以定义指向结构体的指针 。
利用 new运算符可以进行动态地分配内存,利用 delete
运算符可以释放已分配的内存 。
C++允许使用关键字 typedef为已有的数据类型定义新的名称,称为类型定义 。 类型定义只是为已有的数据类型生成一个别名,并不是定义了新的数据类型 。
数据文件的打开和关闭是通过使用 fstream类的成员函数 open和 close来实现的 。 fstream类是用来对文件流进行操作,它和标准输出输入流 ( cout,cin) 一起,是 C++实现流操作的最基本的类,而且它们有一个共同的基 类 ios。
为了能使用这些类的相关函数,还必须在程序中添上相关的包含文件 iostream.h和 fstream.h。
第 2章 C++语言基础本章是学习 C++语言的基础,包括以下几个方面:
1,结构化程序设计方法与面向对象程序设计方法的各自特点,
区别和相互联系 。
2,面向对象的程序设计方法中的有关概念,如类,对象,封装,继承,消息和多态性等 。
3,C++程序的基本组成和框架结构 。
4,掌握 C++语言中的基本数据类型,各种运算符,表达式 。
5,C++数据输入流对象 cin和输出流对象 cout的使用 。
6,程序的 3种基本结构
7,构造数据类型,如数组,结构体,指针等的定义方法,特点和使用方法 。
7,函数的定义,调用及函数调用过程中的参数传递的机理和程序执行流程 。
8,引用的概念及其定义和使用方法 。
返回 2
2.1 从面向过程的程序设计到面向对象的程序设计
2.1.1 传统的结构化程序设计( Structured Programming--
-SP)方法
1,使用 SP方法设计程序的步骤在数据处理过程中,采用的是自顶向下,分而治之的方法,将整个程序按功能划分为几个可独立编程的子过程模块,每一子模块完成指定的子任务,并且提供一个清晰,严格的调用界面,主过程通过调用各子过程完来成全部处理工作 。
数据声明 数据处理 结果输出返回 3
2,SP方法的特点优点:
( 1) 这种程序设计方法力求算法描述准确 。
( 2) 对每一子过程模块容易进行程序正确性证明 。
缺点:
( 1) 这种程序设计方法本质上是面向,过程,的,而
,过程,和,操作,又是不稳定和多变的,因此不能直接反映人类求解问题的思路 。
( 2) 程序代码可重用性差 。 程序中除少数标准库函数外,
每设计一个程序时,程序员几乎从零做起 。 即使重用代码,通常也是通过拷贝或编辑重新生成一份 。
( 3)维护程序的一致性困难。该种方法将数据与对数据进行处理的程序代码分离。
2.1 从面向过程的程序设计到面向对象的程序设计返回 4
2.1.2 面向对象的程序设计( Object-Oriented Programming
----OOP)方法
1,面向对象的有关概念面向对象的程序设计方法强调直接以问题域 ( 现实世界 ) 中的事物为中心来思考和认识问题,并按照这些事物的本质特征把它们抽象为对象,以作为构成软件系统的基础 。
( 1 ) 对象 ( Object ),每个对象都具有属性
( Attribute) 和方法 ( Method) 这两方面的特征 。 对象的属性描述了对象的状态和特征,对象的方法说明了对象的行为和功能,并且对象的属性值只应由这个对象的方法来读取和修改,两者结合在一起就构成了对象的完整描述 。
2.1 从面向过程的程序设计到面向对象的程序设计返回 5
( 2)类( Class),具有相似属性和行为的一组对象,
就称为类。可见,有了类的概念以后,就可以对具有共同特征的事物进行统一描述。
( 3)封装( Encapsulation),封装把对象的属性和方法看成了一个密不可分的整体,从而使对象能够完整地描述并对应于一个具体事物 。
( 4)继承( Inheritance),将客观事物进行归类是一个逐步抽象的过程,反之,将类进行层层分类便是一个概念逐渐细化的过程。
在面向对象的程序设计中,允许在已有类的基础上通过增加新特征而派生出新的类,这称为继承 。 其原有的类称为基类 ( base class),而新建立的类称为派生类 。
2.1 从面向过程的程序设计到面向对象的程序设计返回 6
( 5)消息( Message),在面向对象的程序设计中,由于对象描述了客观实体,它们之间的联系通过对象间的联系来反映。当一个对象需要另外一个对象提供服务时,它向对方发出一个服务请求,而收到请求的对象会响应这个请求并完成指定的服务。这种向对象发出的服务请求就称为消息。
( 6)多态性( Polymorphism),多态性是面向对象的另一重要特征。在通过继承而派生出的一系列类中,可能存在一些名称相同,但实现过程和功能不同的方法
( Method)。
所谓多态性是指当程序中的其他部分发出同样的消息时,按照接收消息对象的不同能够自动执行类中相应的方法。其好处是,用户不必知道某个对象所属的类就可以执行多态行为,从而为程序设计带来更大方便。
2.1 从面向过程的程序设计到面向对象的程序设计返回 7
2,面向对象的程序设计方法 ( OOP方法 )
这种方法将设计目标从模拟现实世界的行为转向了模拟现实世界中存在的对象及其各自的行为。
在 OOP中,将,对象,作为系统中最基本的运行实体,
整个程序即由各种不同类型的对象组成,各对象既是一个独立的实体,又可通过消息相互作用,对象中的方法决定要向哪个对象发消息、发什么消息以及收到消息时如何进行处理等。
2.1 从面向过程的程序设计到面向对象的程序设计方法数据 消息消息返回 8
3,OOP方法的特点
( 1) OOP以,对象,或,数据,为中心 。 由于对象自然地反映了应用领域的模块性,因此具有相对稳定性,可以被用作一个组件去构成更复杂的应用,又由于对象一般封装的是某一实际需求的各种成分,因此,某一对象的改变对整个系统几乎没有影响 。
( 2) 引入了,类,( class) 的概念 。 类与类以层次结构组织,属于某个类的对象除具有该类所描述的特性外,还具有层次结构中该类上层所有类描述的全部性质,OOP中称这种机制为继承 。
( 3) OOP方法的模块性与继承性,保证了新的应用程序设计可在原有对象的数据类型和功能的基础上通过重用、扩展和细化来进行,
而不必从头做起或复制原有代码,这样,大大减少了重新编写新代码的工作量,同时降低了程序设计过程中出错的可能性,达到了事半功倍的效果。
2.1 从面向过程的程序设计到面向对象的程序设计返回 9
2.1.3 面向对象的程序设计方法与结构化程序设计方法的比较
( 1) 传统的结构化程序设计方法以过程为中心构造应用程序,数据和处理数据的过程代码是分离的,相互独立的实体,设计出的程序可重用代码少,且当代码量增加时维护数据和代码的一致性困难 。
( 2) 面向对象程序设计方法中,对象所具有的封装性和继承性使得代码重用成为可能,并大大减少了程序出错的可能性 。
( 3) 面向对象方法吸收了结构化程序设计方法的优点,
同时引入了新概念,新机制并建立了比传统方法更高层次的抽象 。
2.1 从面向过程的程序设计到面向对象的程序设计返回 10
2.2.1 从 C语言到 C++语言
C语言以其如下独有的 特点 风靡了全世界:
( 1) 语言简洁,紧凑,使用方便,灵活 。 C语言只有 32
个关键字,程序书写形式自由 。
( 2) 丰富的运算符和数据类型 。
( 3) 可以直接访问内存地址,能进行位操作,使其能够胜任开发操作系统的工作 。
( 4) 生成的目标代码质量高,程序运行效率高 。
( 5) 可移植性好 。
2.2 C++程序的基本组成返回 11
2.2 C++程序的基本组成局限性,
( 1) 数据类型检查机制相对较弱,这使得程序中的一些错误不能在编译阶段被发现 。
( 2) C本身几乎没有支持代码重用的语言结构,因此一个程序员精心设计的程序,很难为其它程序所用 。
( 3) 当程序的规模达到一定程度时,程序员很难控制程序的复杂性 。
返回 12
2.2 C++程序的基本组成
C++包含了整个 C,C是建立 C++的基础 。 C++包括 C的全部特征和优点,同时添加了对面向对象编程 ( OOP) 的完全支持 。
1980年,贝尔实验室的 Bjarne Stroustrup开始对 C进行改进和扩充 。
1983年正式命名为 C++。
在经历了 3次 C++修订后,1994年制定了 ANSI C++ 标准的草案 。 以后又经过不断完善,成为目前的 C++。
C++仍在不断发展中 。 美国微软公司现已准备推出 C#( C
Sharp) 语言,来代替 C++语言 。
返回 13
2.2.2 C++程序的结构与基本组成一个简单的 C++程序,是由若干个函数构成的,其中有且仅有一个名称为 main的函数存在,下图说明了 C++程序的基本框架结构:
2.2 C++程序的基本组成声明区
#include<…… >
:
函数声明定义全局变量主程序区类型 main(参数行 )
{
程序主体;
}
函数定义区函数定义
{
函数主体;
}
返回 14
1,声明区声明区处在程序文件的所有函数的外部 。
( 1) 包含头文件:如 #include "iostream.h"
( 2) 宏定义:如 #define PI 3.1415926
( 3) 类定义:如 class name{ };
( 4) 结构体定义:如 struct record{ };
( 5) 函数声明:如 void print();
( 6) 全局变量声明:如 float H=2.58;
( 7) 条件编译:如 #ifdef 等 。
2.2 C++程序的基本组成返回 15
2,主程序区主程序以 main()函数开始,是整个程序运行的入口,该函数中可能包含的内容主要有:
( 1) 局部变量的声明:如,int i=1;
( 2) 函数调用:如,y=sin(x);
( 3) 一般运算:如,a=b+c+d/3;
( 4) 结构控制:如,if(a>b) c=a;
( 5) 对象与结构的处理 。
( 6) 文件的处理等 。
2.2 C++程序的基本组成返回 16
图 2.3 C++函数的组成
4,程序举例
2.2 C++程序的基本组成函数定义区函数说明 int max(int a,int b)
函数体
{
int c;
c=a+b;
return(c);
}
3,函数定义区程序中除了 main函数之外,还可以包含其它的函数,
每个函数是由函数说明和函数体两部分构成的。如图 2.3
所示:
返回 17
2.2 C++程序的基本组成声明区
#include "iostream.h"
#include "stdio.h"
void print(); //函数声明主程序区
void main()
{ int i;
char s[80];
print( );
cout<<"What's your name?\n";
cin>>s;
cout<<"How old are you?\n";
cin>>i;
cout<<s<<" is "<<i<<" years old.";}
函数定义区
void print( )
{
printf("printfis also can be used\n");
}
返回 18
上例程序结构可写为如下程序:
【 例 2-1】 一个简单的 C++程序 。
// This is first C++ program
/* C语言的某些特征仍可沿用 */
#include "iostream.h"
#include "stdio.h"
void print(); //函数声明
void main()
{ int i;
char s[80];
2.2 C++程序的基本组成返回 19
print( );
cout<<“What?s your name?\n”; // 用 C++特有的方式输出数据
cin>>s;
cout<<"How old are you?\n";
cin>>i;
//验证结果
cout<<s<<" is "<<i<<" years old.";
}
void print( )
{ printf("printf is also can be used\n");
}
2.2 C++程序的基本组成返回 20
从上例可以看出:
( 1) C语言中原有的规则和语句在 C++中仍可继续使用,
但 C++又增添了很多新的风格 。
( 2) 一个 C++的程序是由一到若干个函数构成的,但其中必须有且仅有一个名称为 main的函数存在 。
( 3) 不管一个程序中有多个函数,只有 main函数整个程序运行时的入口,程序运行时从此函数开始执行 。 但在程序中,main函数所处的位臵可以任意 。
( 4) 一个 C++的函数是由两部分构成的,即函数的说明部分和函数体,函数的说明部分包括了函数的返回值的类型,函数的名称,圆括号,形参及形参的类型说明 。
函数体由一对大括号 {}括起来,其内容是由若干条语句
2.2 C++程序的基本组成返回 21
构成,函数体的内容决定了该函数的功能 。
( 5) C++对程序中的名称是大小写,敏感,的,除特殊情况下,应一律小写 。
( 6) 程序中的注释:可以用 /*………… */或 //( 单行注释 ) 对程序中的内容进行注释 。 二者的区别在于,采用
/*………… */方法时,注释可以写成多行,而采用 //方法时,注释只能写成一行,它可单独占一行,也可写在某行程序代码的末尾 。
( 7) 数据输出:除了使用 printf( )函数,还可使用功能更强大,更方便的 cout对象进行输出数据 。 格式如下:
cout<<数据 1<< 数据 2<<…… << 数据 n
如:上例中的语句 cout<<s<<,is”<<i<<,years old.”; 表示同时输出了变量 s的值,字符串,is”,变量 i的值和字符
2.2 C++程序的基本组成返回 22
串,years old.”
(8) 数据输入:除了使用 scanf( )函数,还可使用功能更强大,更方便的 cin对象进行数据输入 。 格式如下:
cin>>变量 1>>变量 2>>…… >>变量 n
如:上例中的语句 cin>>s;表示给变量 s输入一个值
(9) 在分别使用 cout和 cin进行数据的输出和输入时,
需要在程序的开头嵌入,iostream.h”文件 。 在该头文件中定义了输入输出流对象 cout和 cin等 。
(10) 一个 C++的源程序文件在存盘时,要以,CPP为文件名后缀,而不是,C。
2.2 C++程序的基本组成返回 23
2.3 C++数据类型、运算符和表达式
2.3.1数据类型
( 1) 预定义数据类型 ( 基本数据类型 ) 。 包括字符型,
整型,浮点型,无值型四种,其中浮点型又分为单精度浮点型和双精度浮点型两种 。
( 2) 构造数据类型,包括数组,结构体,共用体 ( 联合 ),枚举,类等 。
本节重点介绍 C++的基本数据类型,有关构造数据类型将在后面章节进行介绍 。
返回 24
2.3.1.1 基本数据类型
2.3 C++数据类型、运算符和表达式数据类型 关键字 字节数 数值范围字符型 char 1 -128~ 127
整 型 int 4 -2147483648~ 2147483647
单精度浮点型 float 4 ± (3.4E-38~ 3.4E38)
双精度符点型 double 8 ± (1.7E-308~ 1.7E308
无值型 void 0 valueless
返回 25
2.3.1.2 类型修饰符
C++还允许在基本数据类型(除 void类型外)前加上类型修饰符,来更具体地表示数据类型。 C++的类型修饰符包括:
signed 有符号
unsigned 无符号
short 短型
long 长型
2.3 C++数据类型、运算符和表达式返回 26
数据类型标识符 字节数 数值范围 常量写法举例
Char 1 -128~ 127?A?,?0?,?\n?
signed char 1 -128~ 127 56
unsigned char 1 0~ 255 100
short [int] 2 -32768~ 32767 100
signed short [int] 2 -32768~ 32767 -3456
unsigned short [int] 2 0~ 65535 0xff
int 4 -2147483648 ~
2147483647
1000
signed int 4 -2147483648 ~
2147483647
-123456
unsigned int 4 0~ 4294967295 0xffff
表 2.2 C++的基本数据类型返回 27
数据类型标识符 字节数 数值范围 常量写法举例
long [int] 4 -2147483648 ~
2147483647
-123456
signed long [int] 4 -2147483648 ~
2147483647
-3246
unsigned long [int] 4 0~ 4294967295 123456
float 4 ± (3.4E-38~ 3.4E38) 2.35,-53.231,
3E-2
Double 8 ± (1.7E-308 ~
1.7E308)
12.354,-2.5E10
long double 10 ± (1.2E-4932 ~
1.2E4932)
8.5E-300
表 2.2 C++的基本数据类型返回 28
说明,
( 1) 表中带 [ ]的部分表示是可以省略的,如 short [int]可以写为 short int 或简写为 short,二者的含义是相同的 。
( 2) 四种修饰符都可以用来修饰整型和字符型 。 用 signed
修饰的类型的值可以为正数或负数,用 unsigned修饰的类型的值只能为正数 。
( 3) 用 short修饰的类型,其值一定不大于对应的整数,
用 long修饰的类型,其值一定不小于对应的整数 。
2.3 C++数据类型、运算符和表达式返回 29
2.3 C++数据类型、运算符和表达式
2.3.1.3 常量
在 C++语言中,数据分为常量和变量两大类 。
由于程序中的数据是有类型的,所以常量和变量都是有类型之分的 。。
常量按照不同的数据类型可以分为,字符型常量,整型常量,浮点型常量,以及字符串常量等 。
程序是根据程序中常量的书写格式来区分它是哪种类型常量的 。
返回 30
1.整型常量在程序中书写整型常量时,没有小数部分。用户可根据需要分别可以用十进制、八进制和十六进制的形式书写:
十进制格式,由数字 0至 9和正,负号组成,书写时直接写出数字,如,123,-516,+1000等 。
八进制格式,以数字 0开头的数字 ( 0至 7) 序列,
0111,010007,0177777等 。
十六进制格式,以 0x或 0X开头的数字 ( 数字 0至 9,字母 a至 z) 序列,如 0x78AC,0xFFFF等 。
2.3 C++数据类型、运算符和表达式返回 31
2.浮点型常量只能用十进制来表示 。 可以用小数或指数形式表示,不分单精度和双精度类型 。 如,34.5,,345,1.5e-3
3.字符型常量
( 1)用一对单引号括起来的一个字符,单引号只是字符与其他部分的分割符,不是字符的一部分,并且,不能用双引号代替单引号。在单引号中的字符不能是单引号或反斜杠。如:
a?,?A?,?#? 合法的字符常量
‘’’,?\? 非法的字符常量
,A” 不代表字符常量
( 2)另一种表示字符常量的方法是使用转义字符。
C++规定,采用反斜杠后跟一个字母来代表一个控制字符,
具有新的含义 。
2.3 C++数据类型、运算符和表达式返回 32
C++中常用的转义字符转义字符 含义 ASCII码值(十进制)
\a 响铃( BEL) 7
\b 退格( BS) 8
\n 换行( LF) 10
\r 回车( CR) 13
\t 水平制表( HT) 9
\v 垂直制表( VT) 11
\\ 反斜杠 92
\? 单引号 39
\” 双引号 34
\0 空格符( NULL) 0
\ddd 任意字符 3位八进制数
\xhh 任意字符 2位十六进制数
2.3 C++数据类型、运算符和表达式返回 33
4.字符串常量用一对双引号括起来的一个或多个字符的序列称为字符串常量或字符串。字符串以双引号为定界符,双引号不作为字符串的一部分。如:
,Hello”,,Good Morning!”,,I say,
\,Goodbye!\””
字符串中的字符数称为该字符串的长度,在存储时,
系统自动在字符串的末尾加以字符串结束标志,即转义字符 ‘ \0?。
5.符号常量常量也可用一个标识符来代表,称为符号常量。如,
#define PRICE 30
main()
{…… }
2.3 C++数据类型、运算符和表达式返回 34
使用符号常量应 注意 以下几个方面:
( 1) 它不同于变量,在作用域内其值不能改变和赋值 。
如:在上例中如再用 PRICE=40;这一语句进行赋值则是错误的 。
( 2)符号常量名一般用大写,而变量名用小写,以示区别。
6,程序中常量的表示方法在程序中的常量有以下三种表示方法:
( 1) 在程序中直接写入常量如,-200,3.4E-10,?A?,‘ 1?,0x120,045,5.35,1000l
int i; char s; float f;
i=20; s=?a?; f=2.0;
2.3 C++数据类型、运算符和表达式返回 35
( 2) 利用 #define定义宏常量一般格式,#define 宏名 常数如,#define PI 3.14
…………
s=2*PI*r;
…………
( 3) 利用 const定义正规常数一般格式,const 数据类型标识符 常数名 =常量值;
说明,
① const必须放在被修饰类型符和类型名前面
② 数据类型是一个可选项,用来指定常数值的数据类型,
如果省略了该数据类型,那么编译程序认为它是 int 类型
2.3 C++数据类型、运算符和表达式返回 36
如,const int a=10; 表示定义了一个初始值为 10的整型常量,它在程序中不可改变,但可用于表达式的计算中,
2.3.1.4 变量
1,变量的概念及特点每一变量就相当于一个容器,对应着计算机内存中的某一块存储单元,用于存储程序中的数据 。 变量的值具有以下两个特点:
( 1),一充即无,,即将一个新数据存放到一个变量中时,该变量中原来的值消失,变量的值变成了新值 。
如:执行完语句 int i; i=10; i=20;后 i的值为 20,而不是 10。
2.3 C++数据类型、运算符和表达式返回 37
( 2),取之不尽,,可将某个变量的值与程序中的其它数据进行各种运算,在运算过程中,如果没有改变该变量的值时,那么,不管用该变量的值进行多少次运算,
其值始终保持不变 。
如:语句 int i,j,k; i=10; j=i+10; k=i+j*5;其中,i的值可无限制地多次使用,但它的值始终保持值 10,因为在程序中没有改变变量 i的值。
2,定义变量程序中的每一变量,都要先定义,后使用 。
定义变量的一般有以下三种格式:
数据类型标识符 变量名;
数据类型标识符 变量名 =初始化值;
2.3 C++数据类型、运算符和表达式返回 38
数据类型标识符 变量名 1[=初始值 1],变量名 2[=初始值
2], ;
如:
char a; //定义字符型变量 a
int i=1000; //定义整型变量 i,i的初始值为 1000;
float a=2,b=3,c; //定义浮点型变量 a,b,c,且 a,b的初始值分别为 2,3。
变量名是每个变量的名称,其命名遵循以下规则:
( 1) 由字母,数字和下划线 ( _) 三类符号排列组合形成,且开头字符必须是字母或下划线 。
( 2) 名称中字符的最大个数是 31个 。
( 3) C++中区分变量名的大小写 。
2.3 C++数据类型、运算符和表达式返回 39
( 4) 变量名不能和 C++中的关键字同名,也不能和用户编制的函数或 C++库函数同名 。 如,int,double或 static都不能作为变量名 。
( 5) 变量名尽量做到,见名知意,。
3,定义变量的位臵在程序中的不同位臵采用不同的变量定义方式,决定了该变量具有不同的特点 。 变量的定义一般可有以下三种位臵:
( 1) 在函数体内部在函数体内部定义的变量称为局部变量,这种局部变量只在进入定义它的函数体时起作用,离开该函数体后该变量就消失 ( 被释放 ),即不再起作用 。 因此,不同函数体内部可以定义相同名称的变量,而互不干扰 。 如:
2.3 C++数据类型、运算符和表达式返回 40
void func1(void)
{ int y;
y=2;
}
void func2(void)
{ int y;
y=-100;
}
在本例中,函数 func1和 func2的函数体内部都分别定义了变量 y,但它们都只能在各自的函数体内起作用,都是局部变量 。
2.3 C++数据类型、运算符和表达式返回 41
( 2) 形式参数当定义一个有参函数时,函数名后面括号内的变量,统称为形式参数 。 如:
int is_in(char *a,char b)
{ while(*a)
if (*a==b)
return 1;
else
a++;
return 0;
}
本例中,函数名 is_in后面括号内的变量 a和 b是该函数的形式参数,
它们都只能在该函数体内起作用,是该函数的局部变量 。
2.3 C++数据类型、运算符和表达式返回 42
( 3) 全局变量,在所有函数体外部定义的变量,其作用范围是整个程序,并在整个程序运行期间有效 。 如:
#include,stdio.h”
int count; //定义 count变量是全局变量
void func1(void);
void func2(void);
int main()
{ count=10;
func1();
return 0; }
2.3 C++数据类型、运算符和表达式返回 43
void func1(void)
{ int temp;
temp=count;
func2();
printf(“count is %d”,count); / /输出 10
}
void func2(void)
{ int count;
for(count=1;count<10;count++)
putchar(?.?);
}
2.3 C++数据类型、运算符和表达式返回 44
2.3.2运算符和表达式程序中对数据进行的各种运算是由运算符来决定的,
不同运算符的运算方法和特点是不同的,从此可以看出,一个运算式子中要涉及到数据及运算符,而运算符是对数据进行指定操作,并产生新值的特殊符号 。
2.3.2.1 算术运算符和算术表达式算术运算符就是对数据进行算术运算,如:加、减、
乘、除等,是在程序中使用最多的一种运算符,C++
的算术运算符如表 2.4所示。
2.3 C++数据类型、运算符和表达式返回 45
运算符 功能 数据类型 例子
- 负号 数值 x=-y;
+ 加 数值 z=x+y;
- 减 数值 z=x-y;
* 乘 数值 z=x*y
/ 除 数值 z=x/y;
% 求余 整数 z=x%y
++ 自加 数值 z++或 ++z
表 2.4 C++的算术运算符
-- 自减 数值 z--或 --z
算术表达式是指由算术运算符,括号将常量,变量,函数,圆括号等连接形成的一个有意义的式子 。 如:
返回 46
(1+x)/(3*x)
(((2*x-3)*x+2)*x)-5
3.14*sqrt(r)
b*b-4.0*a*c
注意,
( 1) 表达式中的括号不管有多少层,一律使用圆括号 。
( 2) 在将一个数学上的运算式子写成对应的 C++的表达式时,要 注意 进行必要的转换 。
① 乘号不能省略 。
② 数学表达式中出现的数学运算函数要用 C++提供的对应的数学运算库函数来代替 。
2.3 C++数据类型、运算符和表达式返回 47
③ 要特别注意表达式中两个整型数相除的情况 。 如:
有一数学表达式为 2/3(f-32),要写成对应的 C++的表达式时,正确地写法应写 2.0/3.0*(f-32)。 而不是 2/3*(f-32)
2.3.2.2 赋值运算符和赋值表达式赋值运算符的功能将某个数据的值赋给某个变量 。
赋值运算符的用法格式:
变量名 赋值运算符 常量,变量或表达式说明:
( 1) 被赋值的目标,即赋值运算符左边的量必须是变量,而不能是常量或表达式 。
2.3 C++数据类型、运算符和表达式返回 48
( 2) C++中的赋值运算符如表 2.5所示 。
( 3) 要注意区分赋值运算符,=” 与数学上的,等号,
间的区别,如:
int x,y; //定义变量 x,y为 int类型变量
x=10; //将变量 x赋成值 10
赋值运算符 例子 等价形式
= x=x+y x=x+y
+= x+=y+z x=x+(y+z)
-= x-=y+z x=x-(y+z)
*= x*=y+z x=x*(y+z)
/= x/=y+z x=x/(y+z)
%= x%=y+z x=x%(y+z)
2.3 C++数据类型、运算符和表达式返回 49
x=x+20; //将 x的值在原值 ( 10) 的基础上再加上值 20后
( 结果为 30) 赋给变量 x
y-=x+5; //等价于 y=y-(x+5);右边表达式的值为 30-
(31+5)=-6,y被赋成值 -6
x%=y+10; //等价于 x=x%(y+10) ;右边表达式的值为
31%(-6+10)=3,y被赋成值 3
2.3.2.3 sizeof运算符
sizeof运算符功能是求某一数据类型或某一变量在内存中所占空间的字节数 。 其使用的一般形式:
sizeof(变量名或数据类型 )或 sizeof 变量名或数据类型如:
2.3 C++数据类型、运算符和表达式返回 50
#include <iostream.h>
void main()
{short int aShort;
int anInt;
long aLong;
char aChar;
float aReal;
cout<<"data type\tmemory used(bytes)";
cout<<"\nshort int\t"<<sizeof(aShort);
cout<<"\ninteger \t"<<sizeof(anInt);
cout<<"\nLong integer\t"<<sizeof(aLong);
cout<<"\nchar achar\t" <<sizeof(aChar);
cout<<"\nfloat \t"<<sizeof(aReal);
}
2.3 C++数据类型、运算符和表达式返回 51
其输出结果为:
data type memory used(bytes)
short int 2
integer 4
Long integer 4
char achar 1
float 4
2.3.2.4 关系运算符和关系表达式关系运算符就是对两个量之间进行比较的运算符,如表 2.6所示 。
2.3 C++数据类型、运算符和表达式返回 52
由关系运算符将两个表达式连接形成的运算式子是关系表达式,
一个关系表达式的值是一个逻辑值,当为真时,值为 1,为假时,值为 0。
如:假设 a=1,b=20,c=3,则
a<b 表达式成立,其值为 1
b==c 表达式不成立,其值为 0
(a+b)!=c表达式成立,其值为 1
关系运算符 含义 例子
< 小于 i>10
<= 小于或等于 (x+y)*2<=100
> 大于 x+y>z
>= 大于或等于 x-y>=a*b+2
= = 等于 x+y==a+b
!= 不等于 x-y!=0
2.3 C++数据类型、运算符和表达式返回 53
注意,
在对两个表达式的值进行是否相等的比较时,要用运算符
,==”,而不能写成,=” 。
2.3.2.5 逻辑运算符和逻辑表达式逻辑运算符是对两个逻辑量间进行运算的运算符,如表
2.7所示 。
2.3 C++数据类型、运算符和表达式逻辑运算符 含义 例子
! 逻辑非 !(x>10)
&& 逻辑与 (i>1) && (i<10)
|| 逻辑或 c==0 || c==9
返回 54
由逻辑运算符将两个表达式连接形成的式子叫逻辑表达式 。 各种逻辑运算的,真值表,如表 2.8所示 。 对于参加逻辑运算的操作数,系统认为,非 0” 为真,,0”
为假 。 而逻辑表达式的结果只能为逻辑真 ( 1) 或逻辑假 ( 0) 。
表 2.8 逻辑运算真值表
a b a&&b a||b !a !b
真 真 真 真 假 假真 假 假 真 假 真假 真 假 真 真 假假 假 假 假 真 真
2.3 C++数据类型、运算符和表达式返回 55
注意,
( 1) C或 C++中在给出一个逻辑表达式的最终计算结果值时,用 1表示真,用 0表示假 。 但在进行逻辑运算的过程中,凡是遇到非零值时就当真值参加运算,遇到 0值时就当假值参加运算 。 如,int a=10,b=15,c=14; 则 ( a+6)
&& (b>c)的值为 1( 真 ) 。
( 2) 在逻辑表达式的求值过程中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的值时,才执行该运算符 。
① a && b && c 只有 a为真时,才需要判别 b的值,只有 a
和 b的值都为真时才需要判别 c的值 。 如,int i=10;则表达式 i && (i=0) && (++i)的值为 0( 假 ),该表达式运算结束后,变量 i的值为 0,而不是 1。
2.3 C++数据类型、运算符和表达式返回 56
② a || b||c 只要 a为真,就不必须判断 b和 c;只有 a为假,
才判别 b; a和 b 都为假才判别 c。 如,int i=1,j; 则表达式
i++||i++||i++的值为 1( 真 ),运算结束后,变量 i的值为 2,
而不是 4。
③ 对于数学上的表示多个数据间进行比较的表达式,在
C或 C++中要拆写成多个条件并用逻辑运算符连接形成一个逻辑表达式 。 如:在数学上,要表示一个变量 a的值处于 -1和 -9之间时,可以用 -9<a<-1。 但在 C++语言中必须写成 a>-9 && a<-1,而不能写成 -9<a<-1。 因为,假设变量 a
当前的值为 -5,它的值确实处在 -1和 -9之间,但在 C++语言中求 -9<a<-1时,从左向右进行计算,先计算 -9<a,得 1
( 真 ),此时该表达式可简化为 1<-1,结果为 0( 假 ) 。
因此必须写成 a>-9 && a<-1的形式 。
2.3 C++数据类型、运算符和表达式返回 57
2.3.2.6 条件运算符在 C++中只提供了一个三目运算符 — 即条件运算符
,?,,,其一般形式为:
表达式 1? 表达式 2:表达式 3
条件运算的规则是:首先判断表达式 1的值,若其值为真
( 非 0),则取表达式 2的值为整个表达式的值;若其值为假 ( 0),则取表达式 3的值为整个表达式的值 。
如:若 a=3,b=4,则条件表达式 a>b?a:b的值为 4。
2.3.2.7 位运算符
1,位运算符及其运算规则所谓位运算符是指能进行二进制位运算的运算符 。 C++
提供的位运算符如表 2.9所示 。
2.3 C++数据类型、运算符和表达式返回 58
位运算的运算规则为:
( 1) 按位与 &:两个运算量相应的位都是 1,则该位的结果值为 1,否则为 0;
( 2) 按位或 |:两个运算量相应的位只要有一个是 1,则该位的结果值为 1,否则为 0;
运算符 含义 例子
& 按位与 i&128
| 按位或 j|64
^ 按位异或 j^12
~ 按位取反 ~j
<< 按位左移 i<<2
>> 按位右移 j>>2
2.3 C++数据类型、运算符和表达式返回 59
( 3) 按位异或 ^:两个运算量相应的位不同,则该位的结果值为 1,否则为 0;
( 4) 按位取反 ~:将运算量的每一位取反 。
( 5) 按位左移 <<:将操作数中的每一位向左移动指定的位数,移出的位被舍弃,空出的位补 0。
( 6) 按位右移 >>:将操作数中的每一位向右移动指定的位数,移出的位被舍弃,空出的位补 0或补符号位 。
如,a=5,b=6,则:
a 00000101 00000101 00000101
b &00000110 | 00000110 ^ 00000110 ~ 00000110
00000100 00000111 00000011 11111001
即,a&b=4,a|b=7,a^b=3,~b=249。
2.3 C++数据类型、运算符和表达式返回 60
2,复合位运算符位运算符与赋值运算符结合可以形成复合位运算符,
如表 2.10所示 。
2.3.2.8 强制类型转换运算符该运算符的功能是将某一数据从一种数据类型向另一运算符 例子 等价形式
&= x&=y+z x=x&(y+z)
|= x|=x+2 x=x|(x+2)
^= x^=y x=x^y
<<= x<<=y+z x=x<<(y+z)
>>= x>>=y+z x=x>>(y+z)
2.3 C++数据类型、运算符和表达式返回 61
种数据类型进行转换 。 其使用的一般形式:
数据类型标识符 ( 表达式 )
( 数据类型标识符 ) 表达式如,int i=2;
float a,b;
a=float(i); //将变量 i的类型强制转换为浮点型,并将其值赋给变量 a
b=(float)i; //将变量 i的类型强制转换为浮点型,并将其值赋给变量 b
2.3.2.9 逗号运算符逗号运算符的运算优先级是最低的 。 一般形式为:
表达式 1,表达式 2,,表达式 N
2.3 C++数据类型、运算符和表达式返回 62
在计算逗号表达式的值时,按从左至右的顺序依次分别计算各个表达式的值,而整个逗号表达式的值和类型是由最右边的表达式决定 。
如:有语句 int a=3,b=4;则表达式 a++,b++,a+b的值为 9。
再如:设有 int i;则表达式 i=1,i++==2?i+1:i+4的值为 6。
2.3.2.10 运算符的优先级与结合性每个运算符都有自己优先级和结合性 。 当一个表达式中包含多个运算符时,要确定运算的结果,必须首先确定运算的先后顺序,即运算符的优先级和结合性 。 C++中运算符的优先级和结合性如表 2.11所示 。
2.3 C++数据类型、运算符和表达式返回 63
优先级 运算符 结合性
1 ( ),,[] ->,,* ->* 自左至右
2 ! ~ ++ -- + - * & (类型 ) sizeof new[] delete[] 自右至左
3 * / % 自左至右
4 + - 自左至右
5 << >> 自左至右
6 < <= > >= 自左至右
7 == != 自左至右
8 & 自左至右
9 ^ 自左至右
10 | 自左至右
11 && 自左至右
12 || 自左至右
13?,自右至左
14 = += -= *= /= %= <<= >>= &= ^= |= 自右至左
15,自左至右表 2.11 C++中运算符的优先级和结合性返回 64
2.4 数据的输入与输出在 C++语言中,数据的输入和结果的输出是分别使用系统所提供的输入流对象 cin和输出流对象 cout来完成的 。
在使用过程中,只要在程序的开头嵌入相应的头文件
,iostream.h” 即可 。
2.4.1 数据的输出 cout
输出流对象输出数据的语句格式为:
cout<<数据 1<<数据 2<< <<数据 n;
说明:
( 1) cout是系统预定义的一个标准输出设备 ( 一般代表显示器 ) ;,<<” 是输出操作符,用于向 cout输出流中插入数据 。
( 2) cout的作用是向标准输出设备上输出数据,被输出的数据可以是常量,已有值的变量或是一个表达式 。
返回 65
如:
#include <iostream.h>
#include <math.h>
void main()
{ float a=3,b=4;
cout<< "The result is,";
cout<<sqrt(a*a+b*b); }
该程序的输出结果为,The result is,5
( 3) 可以在 cout输出流中插入 C++中的转义字符 。 如:
cout<< " the value of a:\n";
cout<<a;
2.4 数据的输入与输出返回 66
表示输出完字符串 Input the value of a:后,在下一行输出变量 a的值 。
( 4) 可以将多个被输出的数据写在一个 cout中,各输出项间用,<<” 操作符隔开即可,但要注意 cout首先按从右向左的顺序计算出各输出项的值,然后再输出各项的值 。
如,cout<<" value of a:"<<a<<" value of b:"<<b<<" The
result is,"<< sqrt(a*a+b*b);
再如:设变量 i的值为 10,则 cout<<i<<","<<i++<<","<<i++;
的输出结果为,12,11,10
( 5) 一个 cout语句也可拆成若干行书写,但注意语句结束符,;” 只能写在最后一行上 。 如:对于上面的语句也可写成如下形式:
2.4 数据的输入与输出返回 67
cout<<" value of a:" //注意行末无分号
<<a
<<" value of b:"
<<b
<<" The result is,"
<< sqrt(a*a+b*b); //在此处书写分号
( 6) 在 cout中,实现输出数据换行功能的方法:既可使用转义字符,\n”,也可使用表示行结束的流操作子 endl。
如:
cout<<"This is first Line.\n"<<"This is second line,";
上面语句可等价地写为:
cout<<"This is first Line."<<endl<<"This is second line,";
2.4 数据的输入与输出返回 68
( 7) 在 cout中还可以使用流控制符控制数据的输出格式,
但使用这些流控制符时,要在程序的头上嵌入头文件
#include <iomanip.h>。 常用的流控制符及其功能如表 2.12
所示 。
表 2.12 I/O流的常用控制符
2.4 数据的输入与输出控制符 功能
dec 十进制数输出
hex 十六进制数输出
oct 八进制数输出
setfill(c) 在给定的输出域宽度内填充字符 c
setprecision(n) 设显示小数精度为 n位
setw(n) 设域宽为 n个字符
setiosflags(ios::fixed) 固定的浮点显示返回 69
2.4 数据的输入与输出
setiosflags(ios::scientific) 指数显示
setiosflags(ios::left) 左对齐
setiosflags(ios::right) 右对齐
setiosflags(ios::skipws) 忽略前导空白
setiosflags(ios::uppercase) 十六进制数大写输出
setiosflags(ios::lowercase) 十六进制数小写输出
setiosflags(ios::showbase) 按十六/八进制输出数据时,前面显示前导符 0x/0;
返回 70
2.4 数据的输入与输出
① 设臵域宽:所谓域宽就是被输出数据所占的输出宽度
(单位是字符数)。设臵域宽可以使用流控制符 setw(n)
和 cout的方法 cout.width(n)
其中 n为正整数,表示域宽。但是,cout.width(n)和
setw(n)二者都只对下一个被输出的数据有作用,若一个输出语句内有多个被输出的数据,而要保持一定格式域宽时,需要在每一输出数据前加上 cout.width(n)或
setw(n)。
此外,当参数 n的值比实际被输出数据的宽度大时,
则在给定的域宽内,数据靠右输出,不足部分自动填充空格符;若被输出数据的实际宽度比 n值大时,则数据所占的实际位数输出数据,设臵域宽的参数 n不再起作用。
返回 71
【 例 2-2】 cout流控制符 setw的使用 。
#include <iostream.h>
#include <iomanip.h>
void main()
{int a=21,b=999;
cout<<setw(3)<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl; }
其输出结果是:
︼ 21︼ ︼ 21︼ ︼ ︼ 21 //程序中第一个 cout的输出结果
999︼ 999︼ ︼ 999 //程序中第二个 cout的输出结果
10201020︼ 1020 //程序中第三个 cout的输出结果
2.4 数据的输入与输出返回 72
② 设臵域内填充字符:在默认情况下,当被输出的数据未占满域宽时,会自动在域内靠左边填充相应个数的空格符 。 但我们也可以设臵在域内填充其他的字符,方法是利用 cout的 fill方法 cout.fill(c)或 setfill(c)。 cout.fill(c)上和 setfill(c)可以对所有被输出的数据起作用 。
【 例 2-3】 在例 2-2的基础上增加域内填充字符的功能 。
#include,iostream.h”
#include,iomanip.h”
void main()
{int a=21,b=999;
cout.fill(‘ #’ ); //设臵域内填充字符为 #字符
cout<<setw(3)<<a<<setw(4)<<a<<setw(5)<<a<<endl;
2.4 数据的输入与输出返回 73
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout.fill(‘ %’ ); //将域内填充字符改为 %字符
cout<<setw(3)<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
}
其输出结果是:
#21##21###21 //程序中第一个 cout的输出结果,未占满域宽的部分填充 #字符 。
999#999##999 //程序中第二个 cout的输出结果
10201020%1020 //程序中第三个 cout的输出结果,未占满域宽的部分填充 %字符 。
2.4 数据的输入与输出返回 74
当采用流控制符设臵填充字符时,上面程序代码也可等价地改为:
#include <iostream.h>
#include <iomanip.h>
void main()
{int a=21,b=999;
cout<<setw(3)<<setfill(‘ #')<<a<<setw(4)<<a<<setw(5)<<a
<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill(‘ %')<<a+b<<setw(4)<<a+b<<setw(5)
<<a+b<<endl;
}
2.4 数据的输入与输出返回 75
③ 设臵输出数据的进位计数制:在默认情况下,被输出的数据按十进制格式输出 。 但可以使用流控制符 hex和 oct控制数据的输出格式为十六进制和八进制,一旦设臵成某种进位计数制后,数据的输出就以该种数制为主,可利用流控制符 dec将数制重新成十进制 。
【 例 2-4】 在例 2-2的基础上增加域内填充字符的功能 。
#include <iostream.h>
#include <iomanip.h>
void main()
{
int a=21,b=999; //设臵以十六制格式输出数据
2.4 数据的输入与输出返回 76
cout<<setw(3)<<setfill('#')<<hex<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill(?%?)<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
//设臵以八制格式输出数据
cout<<setw(3)<<setfill('#')<<oct<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill('%')<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
//设置以十制格式输出数据
cout<<setw(3)<<setfill('#')<<dec<<a<<setw(4)<<a<<setw(5)<<a<<endl;
cout<<setw(3)<<b<<setw(4)<<b<<setw(5)<<b<<endl;
cout<<setw(3)<<setfill('%')<<a+b<<setw(4)<<a+b<<setw(5)<<a+b<<endl;
}
2.4 数据的输入与输出返回 77
程序的输出结果为:
#15##15###15 //以十六进制格式输出数据
3e7#3e7##3e7
3fc%3fc%%3fc
#25##25###25 //以八进制格式输出数据
17471747#1747
17741774%1774
#21##21###21 //以十进制格式输出数据
999#999##999
10201020%1020
2.4 数据的输入与输出返回 78
④ 设臵浮点数的输出格式:对于浮点数,既可以用小数格式输出,也可以用指数格式输出 。 这可以分别通过
setiosflags(ios::fixed)和 setiosflags(ios::scientific)来控制 。
【 例 2-5】 已知圆的半径 r=6.779,计算并输出圆的周长和面积,要求分别用指数和小数两种格式输出 。
#include <iostream.h>
#include <iomanip.h>
void main()
{ const double pi=3.14159;
double r=6.779,c,s;
c=2.0*pi*r; //计算圆的周长
s=pi*r*r; //计算圆的面积
2.4 数据的输入与输出返回 79
//以指数格式输出圆的面积和周长
cout<<"圆的周长 (指数 )为,"<<setiosflags(ios::scientific)<<c<<endl;
cout<<"圆的面积 (指数 )为,"<<s<<endl;
//以小数输出圆的面积和周长
cout<<"圆的周长 (小数 )为,"<<setiosflags(ios::fixed)<<c<<endl;
cout<<"圆的面积 (小数 )为,"<<setiosflags(ios::fixed)<<s<<endl;
}
程序的输出结果如下:
圆的周长 (指数 )为,4.259368e+001
圆的面积 (指数 )为,1.443713e+002
圆的周长 (小数 )为,42.5937
圆的面积 (小数 )为,144.371
2.4 数据的输入与输出返回 80
2.4.2数据的输入 cin
在 C++程序中,数据的输入通常采用 cin流对象来完成,
其格式如下:
cin>>变量名 1>>变量名 2>> >>变量名 n;
说明:
( 1) cin是系统预定义的一个标准输入设备
( 2) cin的功能是:当程序在运行过程中执行到 cin时,
程序会暂停执行并等待用户从键盘输入相应数目的数据,
用户输入完数据并回车后,cin从输入流中取得相应的数据并传送给其后的变量中 。
( 3),>>” 操作符后除了变量名外不得有其他数字,字符串或字符,否则系统会报错 。
2.4 数据的输入与输出返回 81
如,cin>>"x=">>x; //错误,因含有字符串 "x="
cin>>‘ x’ >>x; //错误,因含有字符 ‘ x=’
cin>>x>>10; //错误,因含有常量 10
( 4) cin后面所跟的变量可为任何数据类型,若变量为整型数据类型,则在程序运行过程中从键盘输入数据时,可分别按十进制,八进制或十六进制输入该整数 。 但要 注意,
当按十进制格式输入整数时,可直接输入数据本身即可;
若以十六进制输入整数时,数据前要冠以 0x或 0X;
若按八进制格式输入整数时,数据前要冠以数字 0,。
若 cin后面的变量为浮点类型 ( 单精度或双精度 ) 时,可分别按小数或指数的格式表示该浮点数 。
若 cin后面的变量为字符类型时,可直接输入字符数据而不能在字符的两端加单引号 。
2.4 数据的输入与输出返回 82
( 5) 当程序中用 cin输入数据时,最好在该语句之前用
cout输出一个需要输入数据的提示信息,以正确引导和提示用户输入正确的数据 。 如:
cout<< "请输入一个整数,"
cin>>x;
( 6) 当一个 cin后面同时跟有多个变量时,则用户在输入数据时的个数应与变量的个数相同,各数据之前用一个或多个空格隔开,输入完后按回车键;或者,每输入一个数据按回车键也可 。 如对于以下程序段:
int x;
double a;
char c1;
cout<<"输入一个整数,一个浮点数和一个字符,";
2.4 数据的输入与输出返回 83
cin>>x>>a>>c1;
cout<<"整数,"<<x<<"浮点数,"<<a<<"字符,"<<c1;
运行过程中,屏幕上显示,输入一个整数,一个浮点数和一个字符,”,用户输入数据的格式可以是:
100︼ 3.14︼ a
或者,100︼ ︼ ︼ ︼ 3.14︼ ︼ ︼ a
或者,100
3.14
a
最后程序的输出结果为,,整数,100浮点数,3.14字符,a”
2.4 数据的输入与输出返回 84
2.5.1 C++语句概述语句 ( statement) 是程序中最小的可执行单位 。 一条语句可以完成一种基本操作,若干条语句组合在一起就能实现某种特定的功能 。 C++中语句可以分为以下三种形式:
1,单一语句在任何一个表达式后面加上分号 ( ; ) 就构成了一条简单的 C++语句,例如:
c=a+b;
b++;
a>b?a:b;
cout<<,Hello C++” <<endl;等等 。
2.5 C++的控制语句返回 85
2,空语句仅由单个分号构成的语句,即;
称为空语句 。
空语句不进行任何操作 。 该语句被用在从语法上需要一条语句,但实际上却又不进行任何操作的地方 。
3.复合语句复合语句是用一对花括号 { }括起来的语句块 。 复合语句在语法上等效于一个单一语句 。
使用复合语句应 注意,
( 1) 花括号必须配对使用;
( 2) 花括号外不要加分号 。
2.5 C++的控制语句返回 86
2.5.2 C++程序的三种基本结构在程序设计中,语句可以按照结构化程序设计的思想构成三种基本结构,它们分别是顺序结构、分支结构和循环结构,如图 2.5所示。
顺序结构 分支结构 循环结构图 2.5 程序的三种基本结构
2.5 C++的控制语句语句 A
语句 B
条件
P
语句 A 语句 B
真假条件
P
语句 A
返回 87
1,顺序结构程序按照语句的书写顺序依次执行,语句在前的先执行,
语句在后的后执行,只能满足设计简单程序的要求 。
2,分支结构在分支结构中,程序根据判断条件是否成立,来选择执行不同的程序段 。 也就是说,这种程序结构,能有选择地执行程序中的不同程序段 。
3,循环结构在循环结构中,程序根据判断条件是否成立,来决定是否重复执行某个程序段 。
程序的执行流程和顺序是由程序中的控制语句来完成的,
而控制流程的主要方式是分支和循环 。
2.5 C++的控制语句返回 88
2.5.3 if 语句
if语句是最常用的一种分支语句,也称为条件语句 。 if
语句有三种形式:单分支 if 语句,双分支 if语句和多分支
if语句,如图 2.6所示 。
单分支 if 语句 双分支 if语句
2.5 C++的控制语句真假表达式语句真 假表达式语句 1 语句 2
返回 89
多分支 if语句
2.5.3.1 单分支 if 语句
if(表达式 )
语句真真真假假假表达式
1
表达式
2
语句 1 语句 2 语句 3 语句 4
2.5 C++的控制语句返回 90
其执行过程为:先计算关键字 if后面的表达式的值,若为真,则执行 if后的,语句,部分,否则跳过该,语句,部分 。 不管是否执行,语句,部分,最后都要接着,语句,
部分的后面,继续执行程序的其它部分 。
注意,
( 1) 括号不能省略 。
( 2) 在 if( 表达式 ) 后不能加分号,;,。
( 3) 关键字 if的后面的表达式可以是任意的表达式,只要表达式的值为非 0,即当真值处理,否则当假值处理 。
( 4) if语句的内嵌语句可以是单一语句,也可以是复合语句 。
( 5) 尽量使 if语句的内嵌语句比 if语句缩进,这是良好编程书写风格 。
2.5 C++的控制语句返回 91
如,int x=0,y=2;
if(x=0)
y++;
cout<<x<<y;
运算结束后,变量 y的值为 2,而不是 3,变量 x的值为 0。
2.5.3.2 双分支 if语句双分支 if语句的一般格式为:
if(表达式 )
语句块 1
else
语句块 2
2.5 C++的控制语句返回 92
其执行过程为:先判断表达式的值,若为真,则执行语句块 1,否则执行语句块 2。 不管程序执行语句块 1还是执行语句块 2,最后都要跳到语句块 2的后面接着执行程序中后面的语句 。
注意,
( 1) 语句块 1,语句块 2既可以是单一语句也可以是用 {}
括起来的复合语句 。
( 2) else子句必须与 if子句配对使用,不能单独使用 。
( 3) else子句必须处在 if子句的后面,且 else语句总是和离它最近的前面未配对的 if语句配对 。
【 例 2-6】 输入一个年号,判断是否为闰年,如果是则输出,yes”,否则输出,Not” 。
分析:只要满足下列两个条件之一者,即是闰年 。
2.5 C++的控制语句返回 93
① 年号能被 4整除,但要排除同时能被 100整除;
② 年号能被 400整除 。
#include <iostream.h>
void main()
{ int y;
cout<<"输入一个年号,";
cin>>y;
if ((y%4==0 && y%100!=0) || (y%400==0))
cout<<"Yes";
else
cout<<"Not";
cout<<"\n程序运行结束 ";}
2.5 C++的控制语句返回 94
2.5.3.3 多分支 if语句多分支 if语句是 if语句的嵌套结构,其一般形式为:
if(表达式 1)
语句 1
else if (表达式 2)
语句 2
else if (表达式 3)
语句 3
else if (表达式 N)
语句 N
else
语块 N+1
2.5 C++的控制语句返回 95
【 例 2-7】 输入学生的成绩 score,按分数输出其等级:
score≥90为优,90>score≥80为良,80>score≥70为中等,
70>score≥60为及格,score<60为不及格 。
#include<iostream.h>
void main()
{ float score;
cout<<"Input score(0~100):";
cin>>score;
if(score>=90)
cout<<"Excellent!";
else if(score>=80)
cout<<"Good!";
2.5 C++的控制语句返回 96
else if(score>=70)
cout<<"Right!";
else if(score>=60)
cout<<"Pass!";
else
cout<<"Failed!";
}
注意,在 if语句嵌套中 else与 if配对关系,else与离它最近的 if语句相匹配 。
2.5.4 switch语句
switch语句是多分支语句 。 在 C++中,使用 switch语句可以更方便,更简洁地实现多分支结构 。
2.5 C++的控制语句返回 97
switch语句的一般形式为:
switch(表达式 )
{ case 常数 1:语句 1; break;
case 常数 2:语句 2; break;
………………
case 常数 n:语句 n; break;
default,语句 n+1
}
switch语句的执行过程是:
① 计算 switch语句后面的表达式的值,当表达式的值与某一个 case后面的常量的值相等时,就执行此 case后面的语句,若所有的 case中的常量的值都没有与表达式的值相匹
2.5 C++的控制语句返回 98
配的,就执行 default后面的语句,当没有 default语句时,
则什么也不执行 。
② 执行完一个 case后面的语句后,程序执行的流程转移到下一个 case继续执行。,case 常量,只是起语句标号作用,
并不是在该处进行条件判断。在执行 switch语句时,根据
switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,不再进行判断。只有当遇到 break语句或执行完全部 switch内的语句时,才跳出 switch语句。
【 例 2-8】 输入学生的成绩 score,按分数输出其等级:
score≥90为优,90>score≥80为良,80>score≥70为中等,
70>score≥60 为及格,score<60 为 不 及 格 。
#include<iostream.h>
void main()
2.5 C++的控制语句返回 99
{ float score;
int a;
cout<<"Input score(0~100):";
cin>>score;
a=score/10;
switch(a)
{case 0:
case 9:cout<<"Excellent!";break;
case 8:cout<<"Good!";break;
case 7:cout<<"Right!";break;
case 6:cout<<"Pass!";break;
default:cout<<"Failed!"; }
}
2.5 C++的控制语句返回 100
说明:
① 常数 1~常数 n必须互不相同,且每一常数后面要有冒号
,:,;
② 各 case子句和 default子句的次序可任意;
③ 语句 1~语句 n+1可以为复合语句;
④ 在 switch语句中出现的 break语句并不是必需的,这要根据程序的需要来决定 。 在此 break语句的作用是跳出 switch
语句;
⑤ 各 case子句后面必须是常数,而不能是变量或表达式
2.5.5 循环语句
C++提供了三种循环结构,while循环语句,do-while循环语句和 for循环语句 。
2.5 C++的控制语句返回 101
2.5.5.1 while循环语句
while语句的一般形为:
while(表达式 )
{循环体语句 }
该语句的执行过程:首先判断 while后面的表达式的值,若表达式的值为真,则执行 while的内嵌语句
( 即循环体 ) 一次;然后重复以上过程,直到表达式的值为假时,才退出循环,接着执行循环体语句后面的其它程序语句 。
【 例 2-9】 求
2.5 C++的控制语句
100
1n
n
返回 102
#include<iostream.h>
void main()
{ int i,n;
n=0;
i=1;
while(i<=100)
{ n=n+i;
i++; }
cout<<"n="<<n<<endl;
}
2.5.5.2 do-while 循环语句
do-while语句的一般形式为:
2.5 C++的控制语句返回 103
do
{
循环体语句
} while(表达式 );
该语句的执行过程:首先执行 do-while的内嵌语句(循环体语句)一次,然后再判断 while后面的表达式的值,
若表达式的值为真,则重复执行 do-while的内嵌语句,如此反复,直到表达式的值为假时,循环结束,执行 while
后面的语句。
【 例 2-10】 求
#include<iostream.h>
void main()
2.5 C++的控制语句
100
1n
n
返回 104
{ int i,n;
n=0;
i=1;
do {n=n+i;
i++;}
while(i<=100);
cout<<"n="<<n<<endl;
}
说明:在循环体相同的情况下,while语句和 do-while
语句的功能基本相同 。 二者的区别在于:当循环条件一开始就为假时,do-while语句中的循环体至少会被执行一次,而 while语句则一次都不执行 。
2.5 C++的控制语句返回 105
2.5.5.3 for循环语句
for循环语句的一般格式为:
for(表达式 1;表达式 2;表达式 3)
{ 循环体语句 }
该语句的执行过程是:
① 执行 for后面的表达式 1;
② 执行表达式 2,若表达式 2的值为真,则执行 for语句的内嵌语句 ( 即循环体语句 ),然后执行第 ③ 步,若为假,
则循环结束,执行第 ⑤ 步;
③ 执行表达式 3;
④ 返回继续执行第 ② 步;
⑤ 循环结束,执行 for语句的循环体下面的语句 。
2.5 C++的控制语句返回 106
【 例 2-11】 求 。 用 for语句实现循环 。
#include<iostream.h>
void main()
{ int i,n;
n=0;
for(i=1;i<=100;i++)
n=n+i;
cout<<"n="<<n<<endl; }
2.5.5.4 循环嵌套在一个循环的循环体中又包含另一个循环语句,称为循环嵌套。 C++的三种循环语句可以相互嵌套,构成循环
2.5 C++的控制语句
100
1n
n
返回 107
嵌套 。 以下几种都是合法的循环嵌套:
( 1) for(;;)
{
……
for(;;)
{ }
……
}
( 2) while()
{
……
for(;;)
{ }
do{
……
}while( );
……
}
2.5 C++的控制语句返回 108
( 3) do{
……
for(;;)
{ }
……
}while( );
同样,if语句和 switch语句也可以与这三种语句嵌套使用。
注意,
( 1)循环嵌套时,外层循环和内层循环间是包含关系,
即内层循环必须被完全包含在外层循环中,不得交叉。
( 2)当程序中出现循环嵌套时,这时,程序每执行一次外层循环,则其内层循环必须循环所有的次数(即内层
2.5 C++的控制语句返回 109
循环结束)后,才能进入到外层循环的下一次循环。
2.5.5.5 限定转向语句
C++提供了跳转语句 break和继续语句 continue。
1,break语句
break语句的一般形式为:
break;
该语句只能用于两种情况:
( 1) 用在 switch结构中,当某个 case子句执行完后,使用
break语句跳出 switch结构 。
( 2) 用在循环结构中,用 break语句来结束循环 。 如果在嵌套循环中,break语句只能结束其所在的那层循环 。
2.5 C++的控制语句返回 110
【 例 2-12】 任意输入若干个整数 ( 不多于 50个 ),计算已输入整数之和,直到输入了负数为止 。
#include <iostream.h>
void main()
{ int i,n,sum;
sum=0;
for(i=0;i<=50;i++)
{ cout<<"\nInput number:";
cin>>n;
if(n<0)
break;
2.5 C++的控制语句返回 111
sum+=n; }
cout<<"sum="<<sum<<endl;
}
2.continue语句
continue语句的一般形式为:
continue;
该语句只能用在循环结构中 。 当在循环结构中遇到
continue语句时,则跳过 continue语句后的其他语句结束本次循环,并转去判断循环控制条件,以决定是否进行下一次循环 。
【 例 2-13】 输出 0~ 100之间所有不能被 3整除的数 。
2.5 C++的控制语句返回 112
#include<iostream.h>
void main()
{ int i;
for(i=0;i<=100;i++)
{ if(i%3==0)
continue;
cout<<i<<endl;}
}
2.5.5.6 三种循环的比较
( 1)三种循环可以相互代替;且都可以使用 break和
continue语句限定循环转向;
( 2) while语句和 for语句是先判断条件,后执行循环体,
而 do-while语句是先执行循环体,后判断条件;
2.5 C++的控制语句返回 113
( 3) for语句功能最强,可完全取代 while和 do-while语句;
( 4) while和 do-while语句中循环变量初始化应该在循环前提前完成,并在 while后指定循环条件,循环体中要包含使循环趋于结束的语句,而 for循环可把这些操作放在 for语句当中 。
2.6 数组及其使用前面已经讲过基本数据类型,如,整型,字符型,实型等,
C++语言还提供了构造数据类型,如,数组,结构体,联合体等,有的书中也叫,导出数据类型,,本节先介绍数组 。
数组是由若干相同数据类型的数据所组成的有序集合。
数组中每一个数据又称为数组元素,它们之间具有固定的先后顺序。用一个统一的数组名和下标来唯一地确定数组中的元素。
2.5 C++的控制语句返回 114
2.6 数组及其使用凡是具有一个下标的数组称为一维数组,具有两个或两个以上下标的数组称为多维数组。
2.6.1 一维数组
2.6.1.1 一维数组的定义一维数组定义的一般格式为:
类型说明标识符 数组名 [常量表达式 ];
如,int b[5];
对定义作几点说明,
( 1) 数组名的命名遵循 C++语言标识符的命名规则;
( 2) 数组名后边是用 [ ]括起来的常量表达式,而不能用圆括号 。
返回 115
( 3) 常量表达式表明该数组的长度,即数组中元素的个数 。 如,int b[5];表示 b数组中共有 5个元素 。
( 4) 常量表达式中可以包括常量和符号常量,不能为变量,
即不允许对数组的大小作动态定义 。 如以下定义不正确,
int n;
scanf(“%d”,&n);
int a[n];
2.6.1.2 一维数组的引用一维数组中各元素在内存中所占的存储单元按下标序号顺序存放,C++语言规定,只能逐个引用数组中的元素,
而不能一次引用整个数组,而数组元素的表示形式为:
数组名 [下标 ]
2.6 数组及其使用返回 116
【 例 2-14】 定义一个一维数组,把各元素值清 0,并输出各元素值 。
#include <iostream.h>
void main()
{ int i;
int b[5];
for(i=0;i<=4;i++)
b[i]=0;
for(i=4;i>=0;i--)
cout<<b[i]<<endl;
}
2.6 数组及其使用返回 117
2.6 数组及其使用
2.6.1.3 一维数组的初始化可以用赋值语句或输入语句使数组中的元素得到值,
也可以使数组在运行之前初始化,即在编译阶段使之得到初值,可用以下几种方法:
(1)在定义数组时对数组元素赋以初值,如,
int a[5]={0,1,2,3,4};
将数组元素的初值放在一对大括号内,各值之间用逗号隔开 。 定义后的结果为,a[0]=0,a[1]=1,a[2]=2,a[3]=3,a[4]=4
(2)可以只给一部分元素赋值,如:
int a[5]={0,1,2};
这说明 a 数 组 中 5 个 元 素 只 有 3 个 元 素 赋 初 值 。
即,a[0]=0,a[1]=1,a[2]=2,后两个元素的值为 0。
返回 118
(3)如果想使一个数组中全部元素值为 0,可以写成
int a[5]={0,0,0,0,0};
(4)在对全部元素赋初值时,可以不指定数组的长度 。 如,
int b[5]={0,1,2,3,4};
可写成:
int b[]={0,1,2,3,4};
2.6.2 二维数组
2.6.2.1 二维数组的定义二维数组定义的一般形式为,
类型说明符号 数组名 [常量表达式 ][常量表达式 ]
如,int a[3][4]; 这就定义了一个 3*4(3行 4列 )的数组 。
2.6 数组及其使用返回 119
注意,不能写成 int a[3,4];的形式 。
如,int a[3][4];
可以把它看作是一个一维数组,它有 3个元素 a[0],a[1],a[2],
这每个元素又是一个分别含 4个元素的一维数组:
a[0] a[0][0],a[0][1],a[0][2],a[0][3]
a a[1] a[1][0],a[1][1],a[1][2],a[1][3]
a[2] a[2][0],a[2][1],a[2][2],a[2][3]
C++语言中,二维数组中元素在计算机内存中的存放顺序是:按行存放,即先在内存中存放第一行的元素,再放第二行的元素,如:
a[0][0],a[0][1],a[0][2],a[0][3],[1][0],a[1][1],a[1][2],a[1][3]等
2.6 数组及其使用返回 120
2.6.2.2 二维数组的使用二维数组元素的表示方式为:
数组名 [下标 ][下标 ]
注意 下标不要超过各维的大小。
2.6.2.3 二维数组的初始化对于二维数组有下列初始化方法:
( 1) 分行给二维数组赋初值,如:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
这种赋值方法比较直观,把第一对括号内的数值赋给第一行的元素,第二括号内的数值赋给第二行的元素,
依此类推 。
2.6 数组及其使用返回 121
( 2) 可以将所有数据写在一个花括号内,这时,计算机自动按数组元素在内存中的排列顺序对各元素赋初值 。
如 int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
( 3) 可以只对数组中部分元素初始化 。 如:
int a[3][4]={{1},{5},{9}};
此处的作用表示,a[0][0]元素被赋成 1,a[1][0]元素被赋成
5,a[2][0]元素被赋成 9,而数组中的其他元素被初始化为 0。
( 4) 如果对二维数组的全部元素初始化,则定义数组时第一维长度可以省略,但第二维长度不能省,如:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
可写成,int a[ ][4]=1,2,3,4,5,6,7,8,9,10,11,12};
也可以只对部分元素初始化而省略第一维的长度,但应
2.6 数组及其使用返回 122
分行进行初始化,如:
int a[][4]={{0,0,3},{},{0,10}};
2.6.3 字符数组
1,字符数组的定义用来存放字符型数据的数组为字符数组,数组中的一个元素中只能存放一个字符,整个数组可以存放一个字符串 。。
如,char c[5];
2,字符数组的初始化字符数组的初始化方式同一维数组的初始化类似,如:
char c[5]={?a?,?b?,?c?,?d?,?e?};
3,字符和字符串结束标志:
2.6 数组及其使用返回 123
在 C++语言中字符串是以 ‘ \0?代表结束标志 。
如:,C.program”是 9个字符的字符串,但在内存中占
10个字节,最后一个字节存放 ‘ \0?。
注意,字符串只能用字符数组来保存,不能用一个简单的字符变量保存,另外,字符数组的初始化方式也可写为,char c[10]={“C.program”};
4,字符串的输出:
对于字符串的输出可以采用下列方法来完成:
( 1) 用 cout,格式是:
cout<<字符串或字符数组名;
如:设有,char s[20]={"This is a string."};则 cout<<s;的输出结果为 This is a string.。
也可直接输出字符串,如,cout<<"This is a string."
2.6 数组及其使用返回 124
( 2) 用 cout流对象的 put方法,格式是:
cout.put(字符或字符变量 );
利用这种方法,每次只能输出一个字符,所以要输出整个字符串,应采用循环的方法 。 如:
#include <iostream.h>
void main()
{ char s[20]={"This is a string."};
int i=0;
while (s[i]!='\0')
{ cout.put (s[i]);
i++;
}
}
2.6 数组及其使用返回 125
( 3) 用 cout流对象的 write方法,格式是:
cout.write(字符串或字符数组名,个数 n);
其作用是输出字符串中的前 n个字符 。 如:
#include <iostream.h>
void main()
{ char s[20]={"This is a string."};
cout.write(s,4); }
该程序的输出结果为 This
5,字符串的输入:
除了可以在程序中利用字符数组初始化的方法或赋值方法将字符串存放到字符数组外,还可以采用以下方法,
但要注意,只能用字符数组接收输入的字符串。
2.6 数组及其使用返回 126
( 1) 利用 cin直接输入 。 格式是:
cin>>字符数组名;
如:
#include <iostream.h>
void main()
{ char s[20];
cin>>s;
cout<<s; }
当程序运行时,输入 abcde并回车时,则输出结果为
abcde,但当输入 ab cde时,输出结果为 ab。因此,这种方法输入字符串时,cin只能接收空格符之前的部分。无法完成接收全部的字符串。
2.6 数组及其使用返回 127
( 2) 利用 cin流对象的 getline方法 。 格式是:
cin.getline(字符数组名,输入字符串的最大长度 n);
其中:
① 参数,字符数组名,是存放字符串的数组名称;
② 参数,输入字符串的最大长度 n” 包括字符串结束标记
\0在内 。 如:
#include <iostream.h>
void main()
{ char s[20];
cin.getline (s,20);
cout<<s; }
2.6 数组及其使用返回 128
当程序运行过程中输入 abcdef并回车时,程序的输出结果为 abcdef。 而当输入 ab cdef回车时,程序的输出结果为 ab cdef。 由此可见,该种方法可以接收含有空格符的字符串 。
( 3) 利用 cin流对象的 get方法 。 格式是:
格式 1,cin.get(字符数组名,输入字符串的最大长度 n);
格式 2,[字符变量名 =]cin.get();
说明:
① 格式 1中的两参数的含义同 getline方法 。
② 格式 2表示输入一个字符,如果要保存该字符,则在其左边写上被赋值的变量名和赋值号,如果不保存该字符,
则可写为 cin.get();
2.6 数组及其使用返回 129
#include <iostream.h>
void main()
{ char s[20];
char c;
cin.get(s,10);
cout<<s;
c=cin.get();
cout<<c; }
当程序运行过程中输入 ab cdef并回车时,程序的输出结果为 ab cdef和换行。由此可见,字符串 ab cdef被接收到字符数组 s中,而输入过程中的换行符 \n被接收到了变量 c
中。这说明输入过程中的换行符 \n并未接收,而还残留在输入缓冲区中。这一点也是 cin.get与 cin.getline间的区别。
2.6 数组及其使用返回 130
一个 C++程序是由若干个源程序文件构成的,而一个源程序文件是由若干个函数构成 。
从用户的角度看,有两种不同的函数:库函数和用户自定义函数 。 所谓库函数也称标准函数,由 C++系统提供 。
而用户自定义函数则需要用户先定义,后使用 。
2.7.1 函数的定义
2.7.1.1 函数的定义格式定义函数的一般形式:
函数返回值的数据类型标识符 函数名 ( 形式参数表及其类型 )
{函数体 }
2.7 函数返回 131
2.7 函数如:
void display_larger( int x,int y)
{
if (x<y)
cout<<"The larger is,"<<y<<"\n";
else if(x>y)
cout<<"The larger is,"<<x<<"\n";
else
cout<<"Two values are equal,"<<"\n";
}
返回 132
在 C++中定义函数时 注意,
( 1) 函数的形参及类型说明要采用新的 ANSI标准,即必须放在函数名后面的括号内 。
( 2) 当形参有多个时,必须用逗号隔开 。
( 3) 如果函数是无参函数,括号也不能省略 。
( 4)所有的函数都要先定义,后使用(调用)。
( 5)不能省略函数值的类型,必须表明该函数的函数值的类型,即使该函数没有返回值,也要注明函数值的类型为 void。
2.7 函数返回 133
2.7.1.2 函数的参数和函数的返回值;
所谓调用函数是指在程序中使用了该函数。
主调函数被调函数调用点
1,形式参数和实际参数 ( 形参和实参 )
在调用函数时,大多数情况下,主调函数和被调函数之间有数据传递关系。而函数之间的数据传递就是靠函数的参数进行的,而对无参函数的调用,没有数据传递
2.7 函数返回 134
在定义函数时,函数名后面括号内的变量名为,形式参数,( 形参 ) 。 在调用函数时,函数名后面括号内的表达式为,实际参数,( 实参 ) 。
例,void main()
{int a,b,c;
cin>>x>>y;
c=max(a,b);
cout<<“max is”<<c; }
int max(int x,int y)
{ int z;
z=x>y?x:y;
return(z); }
2.7 函数返回 135
关于形参和实参说明几点:
( 1) 实参可以是变量,常量,或表达式,但必须有确定的值 。 而形参必须是变量 。
( 2) 形参变量,只有存在发生函数调用时,形参才被分配存储单元,在调用结束时,形参所占的内存单元被释放 。
( 3) 实参与形参的类型必须一致,否则会发生,类型不匹配,的错误 。
( 4) 实参对形参的数据传递是,值传递,,即单向传递 。
由实参把数据传给形参,并且存储单元与形参是不同的单元,并将实参对应的值依次传递给形参变量 。 调用结束后,形参单元被释放,而实参单元保留并维持原值 。
2.7 函数返回 136
2,函数的返回值:
( 1) 函数的返回值是通过函数中的 return语句获得的,
return语句的格式为:
return(表达式 );或 return 表达式;
return语句的功能有两个,
(A) 强制程序执行的流程从被调函数返回到主调函数
(B) 给主调函数带回一个确定的函数值如,int max(int a,int b)
{ return(a>b?a:b); }
2.7 函数返回 137
( 2) 函数值的类型:函数返回值的类型就是在定义函数时的函数值的类型 。 在定义函数时,函数值说明的类型和 return语句中的表达式类型不一致时,则以函数类型为准 。
( 3) 如果被调用函数中没有 return语句,为了明确表示函数,不返回值,,要用 viod定义无类型 。
如,viod print()
{ printf(“c language”);
}
这样系统就保证不使函数带回任何值。
2.7 函数返回 138
2.7.2 函数的调用
1,函数调用的格式函数名 ( 实参数 )
如果调用的是无参函数,则实参表可略去,但函数的括号不能省,
如果实参表中有多个参数,之间用逗号隔开,实参的类型,个数应与形参顺序一一对应 。
函数通过下列三种方式完成函数调用:
( 1) 函数调用语句:即以一个函数的调用后面加上,;,
作为一个语句 。 如,printf();
( 2) 函数表达式:即函数出现在一个表达式中,这时要求函数带回一个确定的值以参加表达式的运算 。 如:
c=2*max(a,b);
2.7 函数返回 139
( 3) 函数参数:以函数的调用作为一个函数的实参 。 如:
M=max(a,max(b,c));
2.调用函数时的前提条件在一个函数中调用另一个函数,需要具备的条件:
( 1) 首先被调用的函数必须已经存在的函数 。 如果调用库函数,一般还应在本文件的开头用 #include命令将调用有关库函数时所需用到的信息包含到本文件来 。
( 2) 如果调用用户自己定义的函数,则必须对被调函数的原型进行说明,函数的原型包括:
函数值的类型标识符 被调用函数名 ( 形参及其类型表 ) ;
( 3) 对函数原型的说明,通常放在程序的顶部,也可以存放到一个头文件中,然后利用 #include 语句嵌入到程序中 。
2.7 函数返回 140
3.函数的定义与函数调用间的区别
( 1) 函数的,定义,是一个函数功能的确立,包括指定函数名,函数返回值的类型,形参及其类型,函数体等,
它是一个完整的,独立的函数单位 。
( 2) 函数的,说明,则只是对已经定义好的函数的返回值进行类型的说明,它包括函数名,函数类型和一对括号 。 而不包括形参和函数体 。
( 3) 对函数进行说明的作用是告诉系统,在本程序中将要用到的函数是什么类型,以便在主调函数中按此类型对函数值作相应的处理 。
2.7 函数返回 141
2.7.3 函数的嵌套调用
C++语言中函数的定义是平行的,独立的,所以,函数的定义是不能嵌套进行的,但函数的调用可以 。 嵌套调用即在调用一个函数的过程中,又调用另一函数 。
2.7 函数
main()函数
{
调用 a函数
}
a( )函数
{
调用 b函数
}
b( )函数
{
}
返回 142
在本例中,main函数在执行过程中,调用了函数 a,而函数 a中又调用了函数 b,所以,这就是一种嵌套调用 。
要 注意,在函数嵌套调调用过程中程序执行的流程和返回点的问题 。
2.7 函数返回 143
2.7 函数
2.7.4 函数的递归调用
1,函数递归调用的概念函数的递归调用就是当一个函数在执行的过程中,出现了直接或间接地调用函数本身的函数调用方式 。
下面定义求 n!的函数 。
long fact(long n)
{ if (n==1)
return 1;
return fact(n-1)*n; //出现了函数 fact自己直接调用本
} 身的函数调用要正确地理解函数的递归调用时,程序执行的流程和返回点 。
返回 144
2.7 函数
2,函数递归调用的条件递归调用的条件也是我们在定义一个递归函数时应该遵循的原则 。
( 1) 必须有完成函数任务的语句 。 如:上例求 n!中的
return 1;
( 2) 有一个确定是否能避免递归调用的测试条件 。 如果条件不满足时就递归调用,否则就不再递归调用 。
( 3) 有一个递归调用语句,并且该递归调用语句的参数应该逐渐逼近不满足条件,以致最后断绝递归 。
( 4) 先测试,后递归调用 。 在递归函数定义中,必须先测试,后递归调用 。 也就是说,递归是有条件的,满足了条件后,才可以递归 。
返回 145
2.7 函数
2.7.5 局部变量和全局变量从程序中各个变量起作用的范围 ( 作用域 ) 来看,变量可以分为局部变量和全局变量 。
1,局部变量在一个函数的内部定义的变量就是内部变量 ( 局部变量 ) 。 如:
float f1(int a)
{int b,c; //a,b,c有效
}
void main( )
{int n,m; //m,n有效
……
}
返回 146
2.7 函数对局部变量作以下几点说明:
( 1)局部变量的作用范围(作用域):只局限在定义它的本函数体之内。
( 2)局部变量的生存期(存在的时间):只有当程序执行到本函数时,才给这些局部变量分配存储单元,当本函数执行完毕后,这些局部变量所占存储单元就被释放。
返回 147
2.7 函数
( 3)不同函数体中可以定义相同名字的变量,但它们代表不同的对象,互不干扰。它们在内存占用不同的内存单元。
( 4) 函数的形式参数也是该函数的局部变量,其他函数不能调用 。
( 5) 在一个函数内部,可以在复合语句中定义变量,但这些变量只在本复合语句中有效,因此,复合语句也可称为,分程序,或,程序块,。
返回 148
2.7 函数
2,静态局部变量 ( 局部静态变量 ),
定义方法是:在函数体内定义变量采用:
static 类型标识符 变量名;
特点:
( 1) 静态局部变量本身也是局部变量,因此其作用域也是局限在定义它的本函数体内,当离开本函数体,该变量就不再起作用,但其值还继续保留 。
( 2) 另一方面,静态局部变量又是静态存储类别的变量,
所以,在整个程序运行开始就被分配固定的存储单元 ( 占用静态存储区 ),整个程序运行期间不再被重新分配,所以其生存期是整个程序运行期间 。
( 3) 静态局部变量的赋初值的时间在编译阶段,并不是每发生一次函数调用就赋一次初值 。 当再次调用该函数时,
静态局部变量保留上次调用函数时的值 。
返回 149
2.7 函数
3,全局变量:
在所有函数体外部定义的变量为外部变量 ( 全局变量 ),全局变量可以被本文件中其他函数所调用 ( 使用 ) 。
全局变量的有效范围为:从定义该变量的位臵开始到本程序文件的结束 。 如:
int p=1,q=5; /*全局变量 */
float f1(int a)
{ int b,c
…… }
char c1,c2; /* 全局变量 */
返回 150
2.7 函数
char f2(int x,int y)
{ int i,j;
…… }
main()
{int m,n.;
……
}
对全局变量的几点说明:
( 1) 全局变量在程序的全部执行过程中都占用固定的内存储单元,而不是仅在需要时才开辟单元,所以其生存期是整个程序运行期间 。
返回 151
2.7 函数
( 2) 全局变量的作用范围是整个程序文件 。 全局变量处于文件的开头定义时,其作用范围为整个文件,否则在定义点之前的函数内使用时,应在函数体内或外部用 extern
说明 。 说明的格式是,extern 类型标识符 变量名;
( 3)在一个程序文件中定义的全局变量,要在同一程序的另外一个程序文件中使用时,应在使用它的程序文件中所有函数体内部或外部对所使用的全局变量用 extern说明。
( 4) 在同一个文件中全局变量与局部变量同名时,则在局部变量的作用范围内,全局变量不起作用 。
4,静态全局变量当在所有函数体的外部用如下格式定义变量时,则这种变量称为静态全局变量 。
static 类型标识符 变量名;
返回 152
2.7 函数静态全局变量的特点是:
( 1) 与全局变量基本相同,只是其作用范围 ( 即作用域 )
是定义它的程序文件,而不是整个程序 。
( 2) 静态全局变量属于静态存储类别的变量,所以它在程序一开始运行时,就被分配固定的存储单元,所以其生存期是整个程序运行期间 。
( 3) 使用静态全局变量的好处是同一程序的两个不同的程序文件中可以使用相同名称的变量名,而互不干扰 。
2.7.6 全局函数和静态函数
1,全局函数凡程序中定义的函数,如果未做特别说明,一律都是全局的 。 也就是说,函数从本质上是全局的,一个程序不管有多少个程序文件所组成,在某个程序文件中可以返回 153
2.7 函数调用同一程序的另外一个程序文件中定义的函数,只要对被调函数的原型进行说明即可 。 声明函数原型的语句:
类型标识符 函数名 ( 形参类型表 ) ;
如:假设程序中定义了 max函数,则:
int max(int,int);就是对函数 max原型的声明 。
2,静态函数:
静态函数定义方法为:
static 类型标识符 函数名 ( 形参及其类型 )
{ 函数体 }
注意,这种函数就只能在定义它的程序文件中调用。
2.7.7 内联函数返回 154
2.7 函数
1,内联函数的定义方法和格式:
inline 函数值的类型 函数名 ( 形参及其类型列表 )
{ 函数体 }
如,inline double square(double x)
{ return x*x; }
void main()
{ double x;
cout<<” input a data” ;
cin>>x;
cout<<” the squre is,<<square(x);
}
返回 155
2.7 函数
2,内联函数与普通函数的区别和联系
( 1) 在定义内联函数时,函数值的类型左面有,inline”
关键字,而普通函数在定义时没有此关键字 。
( 2) 程序中调用内联函数与调用普通函数的方法相同 。
( 3) 当在程序中调用一个内联函数时,是将该函数的代码直接插入到调用点,然后执行该段代码,所以在调用过程中不存在程序流程的跳转和返回问题 。 而普通函数的调用,程序是从主调函数的调用点转去执行被调函数,待被调函数执行完毕后,再返回到主调函数的调用点的下一语句继续执行 。
( 4) 从调用机理看,内联函数可加快程序代码的执行速度和效率,但这是以增加程序代码为代价来求得速度的 。
返回 156
2.7 函数
3,对内联函数的限制应 注意,不是任何一个函数都可定义成内联函数 。
( 1) 内联函数的函数体内不能含有复杂的结构控制语句,
如,switch和 while,如果内联函数的函数体内有这些语句,
则编译将该函数视同普通函数那样产生函数调用代码 。
( 2) 递归函数不能被用来作为内联函数 。
( 3) 内联函数一般适合于只有 1~ 5行语句的小函数,对一个含有很多语句的大函数,没有必要使用内联函数来实现。
返回 157
2.7 函数
2.7.8 函数重载
1,什么是函数重载函数重载是指一个函数可以和同一作用域中的其他函数具有相同的名字,但这些同名函数的参数类型、参数个数、返回值、函数功能可以完全不同。如,
#include <iostream.h>
void whatitis(int i)
{ cout<<"this is integer"<<i<<endl;}
void whatitis(char c[])
{ cout<<“this is string”<<c<<endl; }
main()
{ int i=1;
char c[]="abcdef";
返回 158
2.7 函数
whatitis(i);
whatitis(c);
}
在本例中定义了两个名称都叫 whatitis的函数,但它们的形参类型不同 。 因此,这两个函数就是重载函数 。
2,为什么要使用函数重载在原有 C语言中,每个函数必须有其唯一的名称,这样的缺点是所有具有相同功能,而只是函数参数不一样的函数,就必须用一个不同的名称,而 C++中采用了函数重载后,对于具有同一功能的函数,如果只是由于函数参数类型不一样,则可以定义相同名称的函数 。
3,匹配重载函数的顺序由于重载函数具有相同的函数名,在进行函数调用时,
返回 159
2.7 函数系统一般按照调用函数时的参数个数,类型和顺序来确定被调用的函数 。 具体来说,按以下三个步骤的先后次序找到并调用那个函数:
( 1) 寻找一个严格的匹配,即:调用与实参的数据类型,
个数完全相同的那个函数 。
( 2) 通过内部转换寻求一个匹配,即:通过 ( 1) 的方法没有找到相匹配的函数时,则由 C++系统对实参的数据类型进行内部转换,转换完毕后,如果有匹配的函数存在,则执行该函数 。
( 3) 通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,就调用那个函数 。 即:在函数调用处由程序员对实参进行强制类型转换,以此作为查找相匹配的函数的依据 。 如:
返回 160
2.7 函数
#include <iostream.h>
void print(double d)
{ cout<<"this is a double "<<d<<"\n"; }
void print(int i)
{ cout<<"this is an integer "<<i<<"\n"; }
void main()
{ int x=1,z=10;
float y=1.0;
char c='a';
print(x); //按规则 ( 1) 自动匹配函数 void print(int i)
print(y); //按规则 ( 2) 通过内部转换匹配函数
void print(double i)
返回 161
2.7 函数
//因为系统能自动将 float型转换成 double型
print(c); //按规则 ( 2) 通过内部转换匹配函数
void print(int i)
//因为系统能自动将 char型转换成 int型
print(double(z)); //按规则 ( 3) 匹配 void print(double i)
//因为程序中将实参 z强制转换为 double型 。
}
4,定义重载函数时的 注意事项
( 1) 重载函数间不能只是函数的返回值不同,应至少在如:形参的个数,参数类型或参数顺序上有所不同 。
返回 162
2.7 函数
void myfun(int i)
{ }
int myfun(int i)
{ }
这种重载就是错误的 。
( 2) 应使所有的重载函数的功能相同 。 如果让重载函数完成不同的功能,会破坏程序的可读性 。
返回 163
2.7 函数
2.7.9 默认参数的函数
1,默认参数的函数
C++允许在定义函数时给其中的某个或某些形式参数指定默认值,这样,当发生函数调用时,如果省略了对应位臵上的实参的值时,则在执行被调函数时,以该形参的默认值进行运算 。 如:
#include <iostream.h>
void sum(int num=10) //形参默认值
{ int i,s=0;
for(i=1;i<=num;i++)
s=s+i;
cout<<"sum is "<<s<<"\n"; }
void main()
{ sum(100); //提供了实参值,被调函数以 100进行运算,
输出结果为 5050
sum(); //省略实参值,使用形参默认值 10,输出结
} 果为 55
返回 164
2.7 函数
2,使用默认参数的函数的 注意事项
( 1) 默认参数一般在函数说明中提供 。 如果程序中既有函数的说明又有函数的定义时,则定义函数时不允许再定义参数的默认值 。 如果程序中只有函数的定义,而没有说明函数,则默认参数才可出现在函数定义中 。 如:
void point(int x=10,y=20);
void main()
{ }
void point (int x,int y)
{ cout<<x<<endl;
cout<<y<<endl;
}
返回 165
2.7 函数
( 2) 默认参数的顺序:如果一个函数中有多个默认参数时,则形参分布中,默认参数应从右至左逐渐定义 。 如:
void myfunc(int a=1,float b,long c=20); //错误
void myfunc(int a,float b=2.1,long c=30); //正确返回 166
2.8 指针类型及使用
2.8 指针类型及使用
2.8.1 指针的概念一个变量在内存中所占存储单元的地址号就是该变量的指针 。
如,int i;
i=20;
假设 i变量在内存中所占存储单元的地址号为,1000,此时称 1000这个存储地址为变量 i的指针,而 20是变量 i的值 。
2.8.1.1指针变量的定义专门存放其他变量地址的变量称为 指针变量 。 和其他变量的定义类似,指针变量在使用前也必须定义其类型 。 其定义的一般形式为:
类型标识符号 *指针变量名表如,int i=50;
int *ip;
说明:
( 1) 指针变量名前面的 ‘ *’ 表示该变量为指针变量,它不是变量名本身的一部分 。
( 2) 此处的类型标识符是该指针变量所要指向的变量的类型 。
返回 167
2.8 指针类型及使用
( 3) 变量的指针和指向变量的指针变量的区分:指针是某一变量在内存中所占存储单元的地址,是一个地址值 。
而指针变量则是专门存放其他变量的地址的变量,是个变量,如果某一指针变量中存放了另外一个变量的指针,
则称该指针变量是 指向 那个变量的指针变量 。
2.8.1.2 与指针运算有关系的两个运算符
1,&:求某一变量所占存储单元的存储地址 。
如,int i=50;
int *ip;
ip=&i; //&i—— 求变量 i 的存储单元的地址 ( 即指针 )
此时,指针变量 ip存放了变量 i的存储地址 ( 指针 ),因此称指针变量 ip此时是指向变量 i的 。
返回 168
2.8 指针类型及使用
2,*,取出指针变量所指向的变量的内容,后面跟指针变量 。
如,*ip为取出指针变量所指向的变量的内容 。
即由于 ip是指向变量 i的,所以 *ip 与 i是等价的 。
2.8.1.3 指针变量的引用指针变量的引用,即使用指针变量,其使用方法和普通变量的使用原理一致,但要 注意,
( 1) 指针变量是一个变量:一个指针变量和普通变量一样,在内存中也占存储单元,因此一个指针变量也相当于一个容器,所以指针变量也有其指针,这就是指针变量的指针 。
返回 169
2.8 指针类型及使用
( 2) 指针变量内只能存放其他变量的地址,而不能直接存放一个普通数据 。
( 3) 一个指针变量只能指向同一个类型的变量,如上例中指针变量 ip只能总是指向整型变量 。
( 4) 一个指针变量只有先指向某一个变量后,才可利用该指针变量对它所指向的变量进行操作 ( 间接访问 ) 。
【 例 2-15】 指针变量及其使用方法 。
#include<iostream.h>
void main()
返回 170
2.8 指针类型及使用
{ int a,b;
int *ip1,*ip2; //定义了两个指向整型的指针变量 。
a=100;b=100;
ip1=&a;ip2=&b; //将变量 a,b的地址赋给两个拂针变量,
这时,指针变量 ip1指向变量 a,而 ip2指向 b
cout<<a<< ‘ ’ <<b<<endl;
cout<<*ip1<<‘ ’ <<*ip2<<endl;
//等价于 cout<<a<<‘ ’ <b<<endl;
*ip1=200; //等价于 a=200;
*ip2=300; //等价于 b=300;
cout<<*ip1<<' '<<*ip2<<endl;
}
返回 171
2.8 指针类型及使用
2.8.2 const指针
1,指向常量的指针变量的定义与使用
const 类型标识符 *指针变量名;
如,const int *p;
用这种方法定义的指针变量,借助该指针变量只可读取它所指向的变量或常量的值,但不可借助该指针变量对其所指向的对象的值进行修改(即重新赋值)。但是,
可允许这种指针变量指向另外一个同类型的别的变量。
如:
返回 172
2.8 指针类型及使用
include <iostream.h>
void main()
{ const int i=20;
int k=40;
const int *p; //定义指向常量的指针变量 p
p=&i; //指针变量 p指向变量 i
cout<<*p<<i;
*p=100; //该句错误,不可借助 p对它所指向的目标进行重新赋值
p=&k; //可以使 p指向另外一个同类型的变量
cout<<*p<<k;
*p=200; //该句错误
k=200;}
返回 173
2.8 指针类型及使用
2,指针常量指针常量的定义格式为:
类型标识符 * const 指针变量名 =初始指针值;
如,char * const p=”abcde”
用该种方法定义的指针变量,其值 ( 是一个指针值 ),不可进行修改,但可以借助该指针变量对其所指向的对象的值进行读取或修改 。 另外,这种指针在定义时必须初始化 。 如:
返回 174
2.8 指针类型及使用
void main()
{ char s[]="askdfsljfl";
char * const p=s; //必须初始化
p=,xyz” ; //该句错误,不可再使指针变量指向另外一个地址 ( 指针 )
cout<<*p;
*p=‘ s’ ;
cout<<*p;
p++;
*p=‘ q’ ;
cout<<*p; }
返回 175
2.8 指针类型及使用
3,指向常量的指针常量指向常量的指针常量的定义方法为:
const 类型标识符 * const 指针变量名 =初始指针值;
如,int b;
const int * const p=&b;
用这种方法定义的变量,既不允许修改指针变量的值,也不允许借助该指针变量对其所指向的对象的值进行修改 。 另外,该变量在定义时必须初始化 。 如:
返回 176
2.8 指针类型及使用
void main()
{ int a=10; int c=30;
const int b=20;
const int * const p=&a;
const int * const q=&b;
p=&c; //错误
*p=50; //错误
}
返回 177
2.8 指针类型及使用
2.8.3 指针与函数前面讲过,函数的参数可以为整型,实型,字符型等普通变量 。 实参与形参间参数的传递是单向的,值传递,。
但函数的参数也可为指针,它的作用是将一个变量的地址传给被调函数的形参 。 此时主调函数的调用点上的实参必须是地址值 ( 指针 ),而被调函数的形参一定要定义成指针变量的形式此时,被调函数的形参得到的是实参的指针,因此,该形参变量就指向实参,在被调函数中对形参的操作就相当于对它所指向的实参的操作 。
返回 178
2.8 指针类型及使用
【 例 2-16】 交换两个变量的值。
#include<iostream.h>
void swap(int *p1,int *p2) //形参 p1和 p2的要定义成指针变量形式
{ int p;
p=*p1;
*p1=*p2;
*p2=p; }
void main()
{ int a,b;
cin>>a>>b;
swap(&a,&b); //以变量 a和变量 b的地址作为实参值 。
cout<<a<<','<<b; }
返回 179
2.8 指针类型及使用
2.8.3.1 函数的指针一个函数在内存中的起始地址就是该函数的指针 。
在 C++中,函数的名称就代表了该函数的指针 。
指向函数的指针变量的一般定义形式为,
数据类型标识符 (*指针变量名 )( );
在 C++语言中,指针变量可以指向普通变量,它也可以指向函数 。
返回 180
2.8 指针类型及使用
【 例 2-17】 求 a和 b中较大者。
#include "iostream.h"
int max(int x,int y); //声明被调函数 max
void main()
{ int a,b,c;
cin>>a>>b;
c=max(a,b);
cout<<c; }
int max(int x,int y)
{ int z;
if(x>y)
z=x;
else
z=y;
return(z); }
返回 181
2.8 指针类型及使用如果改用指向函数的指针变量的话,则 main函数为,
void main()
{ int (*p)(); //定义了一个指向返回值为 int型的函数的指针变量 p
int a,b,c;
p=max; //将函数 max的首地址 ( 即指针 ) 赋给指针变量 p
cin>>a>>b;
c=(*p)(a,b);
cout<<c;
}
返回 182
2.8 指针类型及使用说明:
( 1) int (*p)() 说明了一个指向返回值为整型数据的函数的指针 。
( 2) p=max 表示把函数的入口地址赋给指针变量 p,那么 *p
就是函数 max.因此 c=(*p)(a,b);和 c=max(a,b)等价 。
注意,
( 1) 函数的调用可以通过函数名调用,也可通过函数指针调用 。
( 2) int (*p)();只是表示定义了一个指向函数的指针变量 。
( 3) 在函数指针变量赋值时,只须给出函数名,不必给出参数,如,p=max; 因为只是传递函数的地址 。
( 4) 对指向函数的指针做象 p+n,p++,p—等算数运算是无意义的 。
返回 183
2.8 指针类型及使用
2.8.3.2 把指向函数的指针变量作函数参数函数的指针变量主要的用途就是把指针作为参数传递到其它函数 。 如,
sub(int (*x1)(),int (*x2)())
{ int a,b,i,j;
a=(*x1)(i);
b=(*x2)(j); }
返回 184
2.8 指针类型及使用
2.8.3.3 返回指针值的函数返回指针值的函数的定义方式为,
类型标识符号 *函数名 (参数名 )
如,int *a(int x,int y)
{…… }
此时,该函数体内的 return语句的形式为,return(指针值 );
返回 185
【 例 2-18】 定义 findmax()函数,其功能是寻找数组中的最大元素,将该元素的下标通过参数返回,并返回其地址值,编程实现 findmax()函数。
#include "iostream.h"
int *findmax(int *array,int size,int *index);
void main()
{int a[10]={33,91,54,67,82,37,85,63,19,68};
int *maxaddr;
int idx;
maxaddr=findmax(a,sizeof(a)/sizeof(*a),&idx);
cout<<idx<<endl;
cout<<maxaddr<<endl;
cout<<a[idx]<<endl; }
int *findmax(int *array,int size,int *index)
{ int max,i;
max=*(array+0);
for (i=1;i<size;i++)
if (max<*(array+i))
{ max=*(array+i);
*index=i; }
return(array+*index); }
返回 186
2.8 指针类型及使用
2.8.4 指针与数组数组的指针即整个数组在内存中的起始地址;
数组元素的指针是数组中某一元素所占存储单元的地址 。
引用数组元素时是利用数组的下标进行的,也可以利用指针来进行,
利用指针引用某一数组元素时,即可以先使一指针变量指向某一数组元素,然后通过该指针变量对它所指向的数组元素进行操作 。
2.8.4.1 指向数组元素的指针变量的定义与赋值指向数组元素的指针变量的定义与以前定义指针变量的方法相同,只要 注意 指针变量定义时的类型要与所要指向的数组的类型一致即可 。
返回 187
2.8 指针类型及使用如,int a[10];
int *p;
p=&a[0]; //把数组元素 a[0]的地址赋给指针变量 p 。
C++语言中规定:数组名就代表数组首地址 。 也就是数组第 0号元素的地址 。 如:
int a[10];
int *p;
p=&a[0]; /*与 p=a;是等价的 */
p=&a[0];与 p=a;是等价的 。 但要 注意,其作用是把数组
a 的起始地址赋给指针变量 p,而不是把数组 a的各元素的地址赋给 p。
返回 188
2.8 指针类型及使用
2.8.4.2 通过指针变量使用数组元素假设 p为指向某一数组元素的指针变量 。 C++语言规定:
p+1指向数组的下一个元素 。 ( 注意不是单纯的 p加 1) 。
设定义了一个数组 a[10],p的初值为 &a[0],即此时 p指向 a[0]
元素,则:
( 1) p+1 或 a+1就是 a[1]元素的存储地址,即它们都指向数组的第 1号元素 a[1]。 所以 *( p+1) 或 *(a+1)就与 a[1]
是等价的 。
( 2) p+i或 a+i就是 a[i]元素的存储地址,即它们都指向数组的第 i号元素 a[i]。 所以 *(p+i)或 *(a+i)就与 a[i]是等价的 。
因此,利用此方法就可访问到数组元素 。 如:
返回 189
2.8 指针类型及使用
main()
{ int a[0];
int *p,i;
for(i=0;i<10;i++)
cin>>a[i];
p=a;
for (i=0;i<10;i++)
cout<<*(p+i); //等价于 cout<<a[i];
}
返回 190
2.8 指针类型及使用对以上讲过的内容再作几点补充说明:
假设已定义了一个数组 a[10],且定义了一个指针变量 p,赋初值 a.即 p=a;,则:
( 1) p++是指向数组元素的下一个元素;即,a[1]。
( 2) *p++的运算,*p++等同于 *(p++),它的作用是先得到
p所指向的元素的值 ( 即 *p),然后再使 p+1。
如,for(i=0;i<10;i++,p++)
cout<<*p++;
( 3) *(p++) 与 *(++p)的作用是不同的。
*(p++)是先取 p的值作 *运算,然后再使 p加 1( 即指向下一个元素 ) ;
*(++p)是先使 p加 1( 即使 p指向下一个元素 ),然后再作 *运算 。
返回 191
2.8 指针类型及使用如:若 p的初值为 a,(即 &a[0]),输出 *(p++)时,得到 a[0]的值,
而输出 *(++p),则得到 a[1]的值 。
( 4) (*p)++表示 p所指的元素值加 1,对上例来说 a[0]++。
( 5) 对于指针的 --( 自减 ) 运算原理同上 。
( 6) 只有指向数组元素的指针变量才可进行自加或自减运算 。
2.8.4.3 数组名作函数参数数组名可以用来作为实参和形参 。 用数组名作实参,
在调用函数时实际上是把数组的首地址传递给形参,这样,实参数组就与形参数组共占同一段内存,那么形参数组中元素的值发生变化后,实参数组中各元素的值也发生变化,但这种变化并不是从形参传回实参的,而是返回 192
2.8 指针类型及使用由于形参与实参数共享同一段内存而造成的,
利用数组名作为函数的参数时可以用以下四种情况实现,
( 1) 形参和实参都用数组名
( 2) 实参用数组名,形参用指针变量
( 3) 实参和形参都用指针变量
( 4) 实参用指针变量,形参用数组名
【 例 2-19】 函数 func是实现数组排序的过程 。 主函数将 8
个整数读入,调用 func排序并输出结果 。
#include <iostream.h>
void func(int *); //func的函数原型
void main()
返回 193
2.8 指针类型及使用
{ int data[8];
int i;
cout<<"\n输入 8个数,";
for ( i =0; i<8; i++ )
cin>>data[i];
func(data);
cout <<"\n排序输出,";
for ( i =0; i<8; i++ )
cout<<data[i]<<",";
cout <<endl<<endl;
}
返回 194
2.8 指针类型及使用
void func(int *s)
{ int i,j;
int work;
for ( i=0; i<8; i++ )
for ( j=i; j<8; j++ )
if (*(s+i)<*(s+j))
{ work=*(s+i);
*(s+i)=*(s+j);
*(s+j)= work;
}
}
返回 195
2.8 指针类型及使用
2.8.5 指针与字符串
2.8.5.1 字符串的指针和指向符串的指针变量字符串在内存中的首地址称字符串的指针在 c++程序中,可以用两种方法来实现字符串的保存:
( 1) 用字符数组来实现
( 2) 用字符串指针实现如,main()
{ char *string=”languaye”;
cout<<string;
}
输出结果,c language
注意,输出时的指针变量的写法是 string而不是 *string。
返回 196
2.8 指针类型及使用
2.8.5.2 字符串指针作函数参数可以采用以下 4种方法:
实参 形参
( 1) 数组名 数组名
( 2) 数组名 字符指针变量
( 3) 字符指针变量 字符指针变量
( 4) 字符指针变量 数组名
【 例 2-20】 将字符串 a复制为字符串 b。
返回 197
2.8 指针类型及使用
#include<iostream.h>
void copy_string(char *from,char *to)
{ for(;*from!='\0';from++,to++)
*to=*from;
to='\0'; }
void main()
{ char a[20]="c language";
char b[20]="very good";
copy_string(a,b);
cout<<a<<endl;
cout<<b<<endl; }
返回 198
2.8 指针类型及使用
2.8.6 指针数组和指向指针的指针,
1,指针数组如果一个数组中的元素均为指针类型的数据,则称这个数组为指针数组 。 其定义方式为,
类型标识符 * 数组名 [数组长度 ]
如,int *p[4] ;
这种指针数组比较适合于处理字符串 。 如,
char *name[3]={,fortranm”,” basic”,” pascal” };
2,指向指针的指针,
前面已经介绍过指针数组,
返回 199
2.8 指针类型及使用如,char *name[3]
说明该数组中的元素都是指针,数组代表了该指针数组的起始地址,name是指向指针型数据的指针 。
定义指向指针的指针变量的方式为:
类型标识符号 **变量名如,char **p;
**p相当于 *(*p),说明指针变量 p是指向一个字符指针变量 ( 指向字符型数据的指针变量 ) 的 。
返回 200
2.9 引用
2.9.1 引用的概念,声明和使用
1.引用及声明方法引用就是某一变量(目标)的一个别名,这样对引用的操作就是对目标的操作。
引用的声明方法:
类型标识符 &引用名 =目标变量名;
如,int a;
int &ra=a; //定义引用 ra,它是变量 a的引用,即别名说明:
( 1) &在此不是求地址运算,而是起标识作用。
( 2)类型标识符是指目标变量的类型。
( 3)声明引用时,必须同时对其进行初始化。
返回 201
2.9 引用
( 4)引用声明完毕后,相当于目标变量名有两个名称,
即该目标原名称和引用名。
( 5)声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,所以系统并不给引用分配存储单元。
2.引用的使用
( 1)一旦一个引用被声明,则该引用名就只能作为目标变量名的一个别名来使用,所以不能再把该引用名作为其他变量名的别名,任何对该引用的赋值就是该引用对应的目标变量名的赋值。
( 2)对引用求地址,就是对目标变量求地址。
返回 202
2.9 引用
【 例 2-21】 引用的定义及使用方法。
#include <iostream.h>
void main()
{ int a,b=10;
int &ra=a; //定义引用 ra,初始化成变量 a,所以 ra是变量 a的引用(别名)
a=20;
cout<<a<<endl;
cout<<ra<<endl; //等价于 cout<<a<<endl;
cout<<&a<<endl; //输出变量 a所占存储单元的地址
cout<<&ra<<endl; //等价于 cout<<&a<<endl;
返回 203
2.9 引用
ra=b; //等价于 a=b;
cout<<a<<endl;
cout<<ra<<endl; //等价于 cout<<a<<endl;
cout<<b<<endl;
cout<<&a<<endl;
cout<<&ra<<endl; //等价于 cout<<&a<<endl;
cout<<&b<<endl;
}
( 3)由于指针变量也是变量,所以,可以声明一个指针变量的引用。方法是:
类型标识符 *&引用名 =指针变量名;
返回 204
2.9 引用如,#include <iostream.h>
void main()
{
int *a; //定义指针变量 a
int *&p=a; //定义引用 p,初始化为指针变量 a,所以 p是
a的引用(别名)
int b=10;
p=&b; //等价于 a=&b,即将变量 b的地址赋给 a。
cout<<*a<<endl; //输出变量 b的值
cout<<*p<<endl; //等价于 cout<<*a;
}
返回 205
( 4)不能建立数组的引用,因为数组是一个由若干个元素所组成的集合,所以就无法建立一个数组的别名。
( 5)引用是对某一变量或目标对象的引用,它本身不是一种数据类型,因此引用本身不占存储单元,这样,就不能声明引用的引用,也不能定义引用的指针。
如,下例中的操作是达不到的。
int a;
int &ra=a;
int &*p=&ra; //错误
( 6)不能建立空指针的引用,如:不能建立
int &rp=NULL;
2.9 引用返回 206
2.9 引用
( 7)也不能建立空类型 void的引用,如:不能建立
void &ra=3;因为尽管在 C++语言中有 void数据类型,但没有任何一个变量或常量属于 void类型。
2.9.2 用引用作为函数的参数
1.引用作为函数的参数一个函数的参数也可定义成引用的形式,如:我们定义交换两个数的函数 swap,将函数的参数定义成引用的形式:
返回 207
2.9 引用
void swap(int &p1,int &p2) //此处函数的形参 p1,p2都是引用
{ int p;
p=p1;
p1=p2;
p2=p;
}
为在程序中调用该函数,则相应的主调函数的调用点处,
直接以变量作为实参进行调用即可,而不需要实参变量有任何的特殊要求。如:对应上面定义的 swap函数,相应的主调函数可写为:
返回 208
2.9 引用
main()
{ int a,b;
cin>>a>>b; //输入 a,b两变量的值
swap(a,b); //直接以变量 a和 b作为实参调用 swap函数
cout<<a<<‘?<<b; //输出结果 }
上述程序运行时,如果输入数据 10 20并回车后,则输出结果为 20 10。
返回 209
2.9 引用
2.几点说明由上例可看出:
( 1)传递引用给函数与传递指针的效果是一样的,这时,
被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
( 2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,这样形参与形参就占用不同的存储单元,所以形参变量的值是实参变量的副本。因此,当参数传递的数据量较大时,用引用比用一般变量传递参数的效率和所占空间都好。
返回 210
2.9 引用
( 3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中需要重复使用,*
指针变量名,的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。
返回 211
2.9 引用
void swap(int *p1,int *p2)
{ int p;
p=*p1; //必须用,*指针变量名,的形式操作目标数据
*p1=*p2;
*p2=p;
}
main()
{ int a,b;
cin>>a>>b;
swap(&a,&b); //必须以变量 a和 b的地址作为实参
cout<<a<<b;
}
返回 212
2.9.3 如何使一个被调函数同时返回多个值由于函数的返回值是通过函数体中的 return语句完成的,
但一个 return语句只能返回一个值,为此,我们可以采用以下方法:
( 1)利用全局变量的方法:可以在程序的开头定义一些全局变量。这样,当被调函数执行完毕后,所需要的数据已保存在了全局变量中,在主调函数中直接读取全局变量的值即可。
( 2)使用指针或数组的方法:因为在指针作为函数的情况下,可将主调函数的某些变量的地址传递给被调函数。
2.9 引用返回 213
( 3)利用引用的方法:通过前面的学习,我们知道,使用引用传递参数,可以在被调函数中改变主调函数中目标变量的值,这种方法实际上就是可以使被调函数返回多个值。
【 例 2-22】 使用引用使函数返回多个值。以下定义了可以同时返回 10个数中的最大值和最小值的函数 max_min。
2.9 引用返回 214
#include <iostream.h>
void max_min(int *p,int n,int &max,int &min); //声明函数 max_min
void main()
{
int a[10];
int ma,mi;
int i;
for(i=0;i<10;i++)
cin>>a[i];
max_min(a,10,ma,mi); //调用函数 max_min
cout<<ma<<mi;
}
2.9 引用返回 215
2.9 引用
void max_min(int *p,int n,int &max,int &min) //形参 max 和 min定义成引用
{
int i=0;
max=*(p+i);
min=*(p+i);
for(i=1;i<n;i++)
{
if (max<*(p+i))
max=*(p+i); //实质上就是对实参变量 ma赋值
if (min>*(p+i))
min=*(p+i); //实质上就是对实参变量 mi赋值
}
}
返回 216
2.9.4 用引用返回函数值要以引用返回函数值,则函数定义时要按以下格式:
类型标识符 &函数名(形参列表及类型说明)
{函数体 }
说明:
( 1)以引用返回函数值,定义函数时需要在函数名前加 &
( 2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
【 例 2-23】 以下程序中定义了一个普通的函数 fn1(它用返回值的方法返回函数值),另外一个函数 fn2,它以引用的方法返回函数值。
2.9 引用返回 217
#include <iostream.h>
float temp; //定义全局变量 temp
float fn1(float r); //声明函数 fn1
float &fn2(float r); //声明函数 fn2
float fn1(float r) //定义函数 fn1,它以返回值的方法返回函数值
{ temp=(float)(r*r*3.14);
return temp; }
float &fn2(float r) //定义函数 fn2,它以引用方式返回函数值
{temp=(float)(r*r*3.14);
return temp;
}
2.9 引用返回 218
void main() //主函数
{float a=fn1(10.0); //第 1种情况,系统生成要返回值的副本(即临时变量)
float &b=fn1(10.0); //第 2种情况,可能会出错(不同
C++系统有不同规定)
//不能从被调函数中返回一个临时变量或局部变量的引用
float c=fn2(10.0); //第 3种情况,系统不生成返回值的副本
//可以从被调函数中返回一个全局变量的引用
float &d=fn2(10.0); //第 4种情况,系统不生成返回值的副本
//可以从被调函数中返回一个全局变量的引用
cout<<a<<c<<d;}
2.9 引用返回 219
2.9 引用
2.9.5 一个返回引用的函数值作为赋值表达式的左值一般情况下,赋值表达式的左边只能是变量名,即被赋值的对象必须是变量,只有变量才能被赋值,常量或表达式不能被赋值,但如果一个函数的返回值是引用时,
赋值号的左边可以是该函数的调用。
【 例 2-24】 测试用返回引用的函数值作为赋值表达式的左值。
#include <iostream.h>
int &put(int n);
int vals[10];
int error=-1;
void main()
返回 220
2.9 引用
{ put(0)=10; //以 put(0)函数值作为左值,等价于
vals[0]=10;
put(9)=20; //以 put(9)函数值作为左值,等价于
vals[9]=10;
cout<<vals[0];
cout<<vals[9];}
int &put(int n)
{ if (n>=0 && n<=9 )
return vals[n];
else { cout<<”subscript error”;
return error; }
}
返回 221
2.9 引用
2.9.6 用 const限定引用声明方式,const 类型标识符 &引用名 =目标变量名;
用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为 const,达到了引用的安全性。
【 例 2-25】
#include,iostream.h”
double &fn(const double &pd)
{ static double ad=32;
ad+=pd;
cout<<pd<<endl;
return ad;
}
返回 222
2.9 引用
#include,iostream.h”
double &fn(const double &pd)
{ static double ad=32;
ad+=pd;
cout<<pd<<endl;
return ad;
}
void main()
{ double a=100.0;
double &pa=fn(a);
cout<<pa<<endl;
a=200.0;
pa=fn(a);
cout<<pa<<endl;
}
程序运行的结果为,100
132
200
332
返回 223
2.9 引用
2.9.7 引用总结
( 1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大对象的传递效率和空间不如意的问题。
( 2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过 const的使用,保证了引用传递的安全性。
( 3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作,程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,
对引用的操作就是对目标变量的操作。
返回 224
2.10 结构体、共用体和枚举
2.10.1 结构体数组中的各元素是属于同一类型的,但有时需要将不同类型的数据组合成一个有机的整体,并且这些数据是相互联系的,这就引出了结构体 。 结构体是由多种类型的数据组成的整体 。 组成结构体的各个分量称为结构体的数据成员 ( 简称成员 ) 。
2.10.1.1 定义结构体定义结构体的一般格式为:
struct 结构体名
{
成员列表
}变量名列表;
返回 225
2.10 结构体、共用体和枚举结构体定义是以关键字 struct开始的,结构体名应是有效的 C++标识符。结构体中的每个成员都必须通过定义来确定成员名及其类型。例如:
struct student
{ int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
}student1;
其中,student是定义的结构体名,该结构体有四个成员变量 num,name,sex,age。 student1是定义的结构体变量。
返回 226
2.10 结构体、共用体和枚举也可以在结构体定义后再定义结构体变量。格式是:
struct 结构体名 变量名列表;
如:
struct student
{
int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
};
struct student student1;
student student1;
返回 227
2.10 结构体、共用体和枚举
2.10.1.2 结构体变量的初始化结构体变量的初始化就是在定义结构体变量的同时,
为其成员提供初值,可采用以下两种方法:
( 1)在定义结构体类型的同时,为结构体变量初始化。
struct 结构体名
{ 成员列表
}变量名 ={初始值列表 };
如,struct student
{int num; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
}student1={9901,"wang",?f?,23};
返回 228
2.10 结构体、共用体和枚举
( 2)利用已有的结构体类型定义结构体变量,并同时初始化。格式是:
结构体名称 变量名 ={值 1,值 2, };
如,student stu={1,”zhang”,?M?,20,90.0};
此时,student1变量中的 num成员的值为 9901,name成员的值为 "wang",sex成员的值为 23。
2.10.1.3 结构体变量的引用定义了结构体变量以后,就可以在程序中使用这些变量 。 引用结构体变量时应 注意,
( 1) 不能将结构体变量作为一个整体来引用,只能引用结构体变量中的成员 。 引用结构体变量中成员的格式为:
结构体变量名,成员名返回 229
2.10 结构体、共用体和枚举如,cout<<student1.name;
此处的,,” 是成员运算符,它的优先级别最高 。
( 2) 若结构体的成员本身又是一个结构体变量,则要使用多个成员运算符,一级一级地找到最低一级的成员进行引用 。
( 3) 对结构体成员变量的使用可像普通那样进行,如:
进行赋值,参加运算等 。 如:
struct student s1,s2;
s1.num=9901;
s2.num=s1.num+1;
返回 230
2.10 结构体、共用体和枚举
( 4) 可以将一个已有值的结构体变量的值直接赋给另外一个相同类型的结构体变量 。 方法是:
结构体变量名 1=结构体变量名 2;
如,student st1={1,”zhang”,?M?,20,90.0};
student st2; st2=st1;
( 5) 可以应用成员的地址 。 也可以引用结构体变量的地址 。 如:
&student.num &st1
返回 231
2.10 结构体、共用体和枚举
2.10.1.4 结构数组结构数组:即数据类型为结构体类型的数组,这样,
数组中的每个元素都属于同一种结构体类型,每一元素都分别包含了结构体中的每个成员 。
1,结构数组的定义
Struct student
{int num;
char name[20];
int age;
float score;
char addr[30];};
student stu[3];
返回 232
2.10 结构体、共用体和枚举这就定义了一个结构数组 stu,它已含三个元素,其中每个元素都为 student类型,且每个数组元素都各自拥有自己的一套结构成员 num,name,age,score和 addr。
2,结构体数组的初始化结构体数组在定义时也可以进行初始化 。 其初始化方法与一般数组的初始化方法基本相同,只是必须为每个元素提供各结构成员的值,如:
struct student
{ int num;
char name[20];
char sex;
返回 233
2.10 结构体、共用体和枚举
int age;
};
student stu[3]={{1,"sum1",?M?,20},
{2,"zhao2",?M?,25},
{3,"qian3",?M?,21}};
2.10.1.5指向结构体类型的指针
1,指向结构体变量的指针结构体变量的指针:是指结构体变量所占内存单元的起始地址 。 因此,可以定义指针变量指向结构体变量 。
此时该指针变量的值就是结构体变量在内存中起始地址 。
【 例 2-26】 指向结构体变量的指针的使用。
返回 234
2.10 结构体、共用体和枚举
#include "iostream.h"
#include "string.h"
void main()
{ struct student //定义结构体类型 student
{long int num;
char name[20];
char sex;
float score;};
student stu1; //定义结构体类型 student的变量 stu1
student *p; //定义 student类型的指针变量 p
p=&stu1; //将结构体变量 stu1的地址赋给指针变量 p
stu1.num=1; //分别给结构体变量 stu1的 num,name、
sex,score成员赋值返回 235
2.10 结构体、共用体和枚举
strcpy(stu1.name,"li lin");
stu1.sex='M';
stu1.score=89;
//输出 stu1各成员的值
cout<<stu1.num<<"\t"<<stu1.name<<"\t"<<stu1.sex<<"\t"
<<stu1.score<<endl;
//借助指针变量 p输出它所指向的结构体变量各成员的值
cout<<(*p).num<<"\t"<<(*p).name<<"\t"<<(*p).sex<<"\t"
<<(*p).score<<endl;
cout<<p->num<<"\t" << p->name<<"\t" << p->sex<<"\t" << p-
>score<<endl;
}
返回 236
2.10 结构体、共用体和枚举程序的运行结果:
1 li lin M 89
1 li lin M 89
1 li lin M 89
可见,三种访问结构体变量各成员的值的结果完全相同 。
程序说明:
( 1) 上例中 (*p).num也可写为 p->num。
( 2) 结构体取成员的运算可以采用以下三种形式:
① 结构体变量名,成员名
② ( *结构体指针变量名 ),成员名
③ 结构体指针变量名 ->成员名
2,指向结构体数组的指针返回 237
2.10 结构体、共用体和枚举
【 例 2-27】 指向结构体数组的指针的使用 。
#include <iostream.h>
struct student
{ int num;
char name [20];
char sex;
int age ;
};
Student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
void main()
返回 238
2.10 结构体、共用体和枚举
{student *p;
for (p=stu;p<stu+3;p++)
cout<<p->num<<"\t"<<p->name<<"\t"<<p->sex<<"\t"<<p-
>age<<endl;
}
程序的输出结果为:
1 li lin M 18
2 sum M 19
3 zhao M 20
把 stu赋给指针变量 p,就表示 p指向了该数组的起始地址 。 p++ 表示 p指向数组的下一个元素,利用这种方法可以访问数组中所有元素的值 。
返回 239
2.10 结构体、共用体和枚举
2.10.1.6 用结构体类型作为函数的参数
1,用结构体类型的变量作函数的参数 (传值 )
在 C++语言中,允许把结构体类型的变量直接作为函数的参数,但要 注意,此时主调函数的调用点上的实参与被调函数相应位臵上的形参必须是相同的结构体类型,是将实参的值 ( 各成员的值 ) 传递给相应的形参 。
【 例 2-28】 用结构体类型的变量作为函数的参数 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
返回 240
2.10 结构体、共用体和枚举
int age ;};
void print(student);
Student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
void main()
{ int i;
for (i=0;i<3;i++)
print(stu[i]);
}
void print(student s)
{ cout<<s.num<<"\t"<<s.name<<"\t"<<s.sex<<"\t"<<s.age<<
"\t"<<endl;}
返回 241
2.10 结构体、共用体和枚举程序的执行结果是:
1 li lin M 18
2 sum M 19
3 zhao M 20
可见,当把一个结构体类型的变量作为函数的参数时,
可以将该变量的值 ( 包含结构体类型中各成员的值 ) 传递给被调函数的形参 。
2,用指向结构体的指针作函数的参数 ( 传指针 )
用指向结构体变量的指针作参数 。 这种方式同指针作为函数的参数的原理一致,传递的是结构体变量的地址 ( 指针 ) 。
返回 242
2.10 结构体、共用体和枚举
【 例 2-29】 用指针的方法实现例 2-28 程序的功能 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
void print(student *);
Student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
返回 243
2.10 结构体、共用体和枚举
void main()
{ int i;
for (i=0;i<3;i++)
print(&stu[i]);}
void print(student *s)
{cout<<s->num<<"\t"<<s->name<<"\t"<<s->sex<<"\t"<<
s->age<<"\t"<<endl;}
3,用结构体变量的引用作为函数的参数此时,被调函数的形参必须声明成引用形式,函数的形参作为实参的一个别名来使用,从而达到对实参操作的目的 。
返回 244
2.10 结构体、共用体和枚举
【 例 2-30】 用结构体变量引用的方法实现例 2-28程序的功能 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
void print(student &);
student stu[3]={{1,"li lin",'M',18},{2,"sum",'M',19},
{3,"zhao",'M',20}};
返回 245
2.10 结构体、共用体和枚举
void main()
{ int i;
for (i=0;i<3;i++)
print(stu[i]);
}
void print(student &s)
{ cout<<s.num<<"\t"<<s.name<<"\t"<<s.sex<<"\t"<<s.age<<
"\t"<<endl;}
2.10.1.7 返回结构体类型的函数
1,返回结构类型值的函数的定义其定义格式如下:
返回 246
2.10 结构体、共用体和枚举结构体名称 函数名 ( 形参及类型说明 )
{ 函数体 }
【 例 2-31】 定义一个返回结构体类型的函数,求所有同学中年龄最大的同学 。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
student max(student *,int);
返回 247
2.10 结构体、共用体和枚举
Studentstu[3]={{1,"lilin",'M',18},{2,"sum",'M',19},{3,"zhao",'M',20}};
void main()
{ student maxold;
maxold=max(stu,3);
cout<<maxold.num<<"\t"<<maxold.name<<"\t"<<maxold.age<<endl; }
student max(student *s,int n)
{ int i,age1,index;
age1=s->age;
index=0;
for (i=0;i<n;i++)
if (age1<(s+i)->age)
{ index=i;
age1=(s+i)->age; }
return (*(s+index));
}
返回 248
2.10 结构体、共用体和枚举
2,返回结构的引用的函数与返回其它类型引用的函数的定义方法和原理一致,
但注意不要返回一个局部变量的引用就可 。
2.10.1.8 结构的嵌套
C++语言中,允许定义一个结构体类型,该结构类型中可以包含另外一种结构类型的成员 。 如下例中定义了一个
birthday结构体类型,它含有 year,month,day三个成员;
又定义了第二个结构体类型 student,它含有 num,sex和
birth三个成员,其中 birth成员是 birthday结构体类型 。
struct birthday{int year;int month;int day;};
struct student
{int num;
char sex;
返回 249
2.10 结构体、共用体和枚举
birthday birth; };
student stu; //定义 student结构体类型的变量 stu
此时要访问 stu的 birth成员的值时,要注意使用多个,,”
操作符 。 如,stu.birth.year=1980;
注意,C++语言中,不能定义一个结构体类型,该结构类型中包含自身结构类型的成员 。 但可包含指向自身结构类型的指针 。 如:
可定义,struct student {int num;char name[20];float score;
student *next;};
不可定义,struct student {int num;char name[20];float score;
student next;};
返回 250
2.10 结构体、共用体和枚举
2.10.2 堆内存的分配和释放堆内存就是在程序的运行过程中根据需要而动态分配的一块内存,因此这种内存分配方式是动态分配,而不是静态分配 ( 如:数组 ) 。
2.10.2.1 申请分配内存的方式从内存中申请分配内存的方法有以下两种:
( 1) 利用 malloc函数格式是,void * malloc(字节数 )
该函数如分配内存成功,则返回其起始地址,否则返回 NULL。当程序中使用 malloc函数动态分配内存时,应该在程序的头部嵌入相应的头文件,#include <stdlib.h>
返回 251
2.10 结构体、共用体和枚举如,int *p;
p=(int *)malloc(sizeof(int));
student *ps;
ps=(student *)malloc(sizeof(student));
( 2) 利用 new运算符:
格式 1:指针变量名 =new 类型标识符;
格式 2:指针变量名 =new 类型标识符 ( 初始值 ) ;
格式 3:指针变量名 =new 类型标识符 [内存单元个数 ];
功能:如果分配内存成功,则返回其起始地址,否则返回 0
注意,格式 1和格式 2都是申请分配某一数据类型所占字节数的内存空间;但是在内存分配成功后,同时将一初值存放到该内存单元中;而格式 3可同时分配若干个内存单元,
相当于形成一个动态数组。
返回 252
2.10 结构体、共用体和枚举如,int *p,*q;
student *r;
p=new int; //申请分配 1个 int类型的内存空间 ( 4个字节 )
p=new int(10); //申请 1个 int类型的内存空间,同时将该内存单元中放臵值 10
q=new int[100]; //申请分配 100个 int类型的内存空间 (200B)
r=new student; //申请分配 1个 student类型的内存空间
( sizeof(student)个字节 )
两种方法的区别:使用 malloc函数分配内存时,其返回值要经过类型转换后才可赋给一个指针变量,而利用
new分配内存时则不需要类型转换 。
返回 253
2.10 结构体、共用体和枚举
2.10.2.2 释放内存的方式在 C++语言中,当不再使用动态分配的内存空间时,
可以将这部分内存释放,以方便其他程序代码使用 。
( 1) 利用 free函数 。
格式,free(起始内存地址 );
使用时应嵌入相应的头文件,#include <stdlib.h>
( 2) 利用 delete运算符:
格式 1,delete 指针变量名;
格式 2,delete [ ] 指针变量名;
说明:格式 1可释放某一个内存单元;而格式 2可释放若干个内存单元的空间。如:
#include <iostream.h>
#include <stdlib.h>
返回 254
2.10 结构体、共用体和枚举
void main()
{ int *number,*p,*q;
number=new int[100]; //申请分配 100个 int类型所占内存空间
p=new int; //申请分配一个 int类型所占内存空间 ( 2个字节 )
q=(int *)malloc(10*sizeof(int)); //申请分配 10个 int类型所占内存空间
if (number==NULL || p==NULL || q==NULL)
cout<<"内存分配失败 "<<endl;
else
cout<<"内存分配成功 "<<endl;
//程序的其它部分
delete []number; //释放 number所指向的所有内存空间
delete p; //释放 p所指向的所有内存空间
free (q); //释放 q所指向的所有内存空间
}
返回 255
2.10 结构体、共用体和枚举
2.10.3 共用体类型
1,共用体概念有时需要使几中不同类型的变量放到同一段内存单元中,如:把一个 int型变量,char 型变量,float型变量放于同一地址开始的内存单元中,这三个变量在内存中占的字节数不同,但都从同一地址开始存放,也就是使用覆盖技术,几个变量相互覆盖,这种使几个不同的变量共一段内存的结构称为共用体类型的结构也叫联合 。
2,共用体类型的定义其定义格式为:
union 共用体名
{成员表 } 变量表;
返回 256
2.10 结构体、共用体和枚举如,union data {int i;
char ch;
float f;
}a,b,c;
这表示定义了共用体类型 data,并同时定义了属于该种数据类型的变量 a,b,c。
由此可见:其定义方式与结构的定义方式类似,但二者的含义不同,结构体变量所占内存空间的大小,是各成员所占的内存之和,每个成员分别占有自己的内存单元,而共用体变量所占的内存空间大小于等于占用内存空间最大的成员的长度,如上面定义的 a,b,c三个共用体变量分别占 4个字节 。
返回 257
2.10 结构体、共用体和枚举
3,共用体变量的定义
( 1) 方法 1:在定义共用体类型的同时定义该种类型的变量,如上例中的变量 a,b,c就是在定义 union data类型的同时定义的共用体变量 。
( 2) 方法 2:可以用已定义过的共用体数据类型,定义共用体变量 。 格式是,union 共用体名称 变量名表;
如,union data mydata;
4,共用体变量的引用共用体变量的使用方法基本同结构体变量的使用方法,
并同时 注意 以下原则:
( 1) 不能直接使用共用体变量,而只能使用共用体变量的成员,共用体变量取成员的运算符同结构体变量取成员的运算符,即用,,” 。
返回 258
2.10 结构体、共用体和枚举如:对于上例定义的共用体变量 a来说,可用以下方法引用其中的成员:
a.i 引用共用体变量 a中的整型变量 i
a.ch 引用共用体变量 a中的整型变量 ch
a.f 引用共用体变量 a中的整型边量 f
( 2) 共用体类型的特点:共用体类型可以使用覆盖技术使几个不同类型的变量 ( 成员 ) 共同占用和使用一块内存空间,所以,在每一瞬时只有一个成员起作用,其他的成员不起作用 。
( 3) 共用体变量中当前正在起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用,如:
返回 259
2.10 结构体、共用体和枚举
a.i=1;
a.ch=‘ a?;
a.f=1.5;
在完成以上三个赋值语句后,只有 a.f有效 。
( 4) 共用体变量的地址和各成员的地址都是同一地址 。
如,a&a &a.i,&a.f同一地址值 。
2.10.4 枚举类型
1,枚举类型及其定义方法如果一个变量只有几种可能的取值时,就可以把它定义为枚举类型,所谓枚举就是指将某一变量所有可能的取值一一列举出来 。 枚举类型的定义格式是:
enum 枚举类型名 {枚举元素表 }枚举变量名;
返回 260
2.10 结构体、共用体和枚举如,enum weekday{sun,mon,tue,wed,thu,fri,sat} workday;
这表示定义了枚举类型 weekday,并同时定义了属于该种类型的变量 workday,该变量的取值范围为 sun~sat。 其中
sun~sat称为枚举元素,是 weekday枚举类型变量的所有可能取值 。
2,枚举变量的定义
( 1) 方法 1:在定义枚举类型的同时定义该种类型的变量,
如上例中的变量 workday就是在定义 enum weekday类型的同时定义的枚举变量 。
( 2) 方法 2:可以用已定义过的枚举数据类型,定义枚举变量 。 格式是:
enum 枚举名称 变量名表;
如:可以利用已有的枚举类型 weekday定义变量 enum
weekday myworkday;
返回 261
2.10 结构体、共用体和枚举
3,枚举变量的使用方法
( 1) 由于枚举类型中列出了该种类型变量的所有可能取值,所以可以将某一枚举元素赋给该种类型的变量,
如,workday=mon;是可以的 。
( 2) 在 c++中,对枚举元素作常量处理,所以枚举元素不是变量,不能对它们赋值,如,sun=0; mon=1;不对 。
( 3) 枚举元素作为常量,它们是有值的,C++语言编译系统按定义时的顺序使它们的值为 0,1,2……
如,enum weekday{sun,mon,tue,wen,thu,fri,sat}workday;
中,枚举元素 sun的值为 0,mon元素的值为 1, 。
如果有赋值语句 workday=thu;则说明变量 workday的值为 4。
返回 262
2.10 结构体、共用体和枚举
( 4)当需要改变枚举元素的默认值时,可以在定义枚举类型的同时在枚举元素的后面用,枚举元素 =值,的格式改变,
如,enum weekday {sun=7,mon=1,tue,wed,thu,fri,sat};
2.10.5 类型定义 typedef的使用在 C++语言中,除了可以直接用 C++提供的标准类型名
int,char,floot,double,long去定义类型外,还可以用 typedef定义新的类型名代替已有的类型名 。 如,
Typedef int INTEGER;//为 int类型定义一个新的名称 INTEGER
typedef float REAL; //为 float类型定义一个新的名称 REAL
INTEGER a,b; //定义变量 a,b为 int类型,等价于 int a,b;
REAL c; //定义变量 c为 float类型,等价于 float c;
返回 263
2.10 结构体、共用体和枚举又如,
typedef struct student
{int num;
char name[10];
int score;
}STUDENT; //为结构体类型 struct student定义新的名称 STUDENT
STUDENT a,b; // 定义 a,b为 struct student类型,等价于 struct student a,b;
注意,
( 1) 类型定义名一般用大写 。
( 2) 类型定义只是给已经存在的数据类型增加一个类型名,而没有创造一个新的数据类型 。
返回 264
2.10 结构体、共用体和枚举
2.10.6 编译预处理在 C++程序的源代码中可以使用各种编译指令,这些指令称为编译预处理命令 。 C++提供的预处理命令主要有以下三种:
宏定义命令
文件包含命令
条件编译命令这些命令在程序中都是以,#” 来引导,每条预处理命令必须单独占用一行;它们不是 C++的语句,因此在结尾没有分号,;,。
1,宏定义命令返回 265
2.10 结构体、共用体和枚举宏定义的一般形式为:
#define 宏名 字符串其中,define是宏替换的关键字,,宏名,是需要替换的标识符,,字符串,是被指定用来替换的字符序列 。
如,#define PI 3.1415926
说明:
( 1) #define,宏名和字符串之间一定要有空格 。
( 2) 宏名一般用大写字母表示,以区别于普通标识符 。
( 3) 宏被定义以后,一般不能再重新定义 。 但可以用
#undef来终止宏定义 。
( 4) 一个定义过的宏名可以用来定义其他新的宏,但要注意其中的括号 。 如:
返回 266
2.10 结构体、共用体和枚举
#define A 20
#define B (A+10)
( 5) 还可以有带参数的宏替换 。 如:
#define MAX(a,b) ((a)>(b)?(a):(b))
2,文件包含命令所谓,文件包含,是指将另一个源文件的内容合并到当前程序中 。 C++中,文件包含命令的一般形式为:
#include<文件名 > 或 #include”文件名,
文件名一般是以,h为扩展名,因而称它为,头文件,,
文件包含的两种格式区别在于:将文件名用,< >” 括起来,用来包含那些由系统提供的并放在指定子目录中头返回 267
2.10 结构体、共用体和枚举文件;将文件名用双引号括起来的,用来包含用户自己定义的放在当前目录或其他目录下的头文件或其他源文件 。
文件包含可以将头文件中的内容直接引入,而不必再重复定义,减少了重复劳动,节省了编程时间 。
注意,一条 #include命令只能包含一个文件,若想包含多个文件,则应使用多条包含命令 。
3,条件编译命令在一般情况下,源程序中的所有语句都会参加编译,
但是有时候会希望根据一定的条件编译源文件的部分语句,这就是,条件编译,。 条件编译使得同一源程序在不同的编译条件下得到不同的目标代码 。
在 C++中,常用的条件编译命令有如下三种:
返回 268
2.10 结构体、共用体和枚举
( 1) #ifdef 标识符程序段 1
#else
程序段 2
#endif
该条件编译命令的功能是:如果在程序中定义了指定的,标识符,时,就用程序段 1参与编译,否则,用程序段 2参与编译 。
( 2) #ifndef 标识符程序段 1
#else
程序段 2
#endif
返回 269
2.10 结构体、共用体和枚举该条件编译命令的功能是:如果在程序中未定义指定的,标识符,时,就用程序段 1参与编译,否则,用程序段 2参与编译 。
( 3) #if 常量表达式 1
程序段 1
#elif常量表达式 2
程序段 2
#elif常量表达式 n
程序段 n
#else
程序段 n+1
#endif
返回 270
2.10 结构体、共用体和枚举该条件编译命令的功能是:依次计算常量表达式的值,
当表达式的值为真时,则用相应的程序段参与编译,如果全部表达式的值都为假,则用 else后的程序段参与编译 。
2.10.7 文件及其操作文件是指存储在存储介质上的数据的集合 。 C++将文件看作是由一个一个字符 ( 字节 ) 的数据顺序组成的 。 它的组成形式可以分为,ASCII文件和二进制文件 。 ASCII
文件又称文本文件,它的每一个字节存放一个 ASCII代码,
代表一个字符;二进制文件是将数据用二进制形式存放在文件中,它保持了数据在内存中存放的原有格式 。
无论是文本文件还是二进制文件,都需要用,文件指针,
来操纵。一个文件指针总是和一个文件相关联,当文件每一次打开时,文件指针指向文件的开始,随着对文件的操作,文件指针不断地在文件中移动,并一直指向最返回 271
2.10 结构体、共用体和枚举后处理的字符 ( 字节 ) 位臵 。
对文件的操作有两种方式:顺序文件操作和随机文件操作 。
2.10.7.1 顺序文件操作顺序文件操作,即从文件的第一个字符 ( 字节 ) 开始,
顺序地处理到文件的最后一个字符 ( 字节 ),文件指针相应地从文件的开始位臵到文件的结尾 。
顺序文件操作包括打开文件,读写文件和关闭文件三个步骤 。
文件的打开和关闭是通过使用 fstream类的成员函数 open
和 close来实现的 。 fstream类是用来对文件流进行操作,
它和前面的标准输出输入流 ( cout,cin) 一起,是 C++实现流操作的最基本的类,而且它们有一个共同的基类 ios。
为了能使用这些类的相关函数,还必须在程序中添上相返回 272
2.10 结构体、共用体和枚举关的包含文件,例如,cout和 cin的头文件是 iostream.h,
而 fstream类的头文件是 fstream.h。
1,打开文件打开文件应使用成员函数 open( ),该成员函数的函数原型为:
void open(const unsigned char *filename,int mode,int
access=filebuf::openprot);
其中,filename是一个字符型指针,指定要打开的文件名; mode指定文件的打开方式,其值如表 2.13所示;
access指定了文件的系统属性,其取值为:
0 一般文件 2 隐藏文件
1 只读文件 3 系统文件表 2.13 在 ios类中定义的文件打开方式返回 273
2.10 结构体、共用体和枚举文件打开方式 含 义
in 以输入 ( 读 ) 方式打开文件
out 以输出 ( 写 ) 方式打开文件
app 打开一个文件使新的内容始终添加在文件的末尾
ate 文件打开时,文件指针位于文件尾
trune 若文件存在,则清除文件所有内容;否则,创建新文件
binary 以二进制方式打开文件,缺省时以文本方式打开文件
nocreat 打开一个已有文件,若该文件不存在,则打开失败
noreplace 若打开的文件已经存在,则打开失败
ios::in|ios::out 以读 /写方式打开文件
ios::in|ios::binary 以二进制读方式打开文件
ios::out|ios::binary 以二进制写方式打开文件表 2.13 在 ios类中定义的文件打开方式返回 274
2.10 结构体、共用体和枚举
2,关闭文件在文件操作结束时,应及时调用成员函数 close()来关闭文件 。 如要关闭的文件名为 myfile,则可使用如下语句关闭文件:
myfile.close();
3,文件的读写在打开文件后,就可以对文件进行读写操作了 。
【 例 2-32】 向文本文件中分别写入一个整数,一个浮点数和一个字符串,并读出其中的信息 。
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
返回 275
2.10 结构体、共用体和枚举
void main()
{ fstream myfile;
myfile.open("f1.txt",ios::out); //以写方式打开文件 f1.txt
if(!myfile)
{ cout<<"Can't open file!!"<<endl;
abort(); //退出程序,包含在 stdlib.h中
}
myfile<<20<<endl;
myfile<<4.58<<endl;
myfile<<"Hello World!"<<endl;
myfile.close();
}
返回 276
2.10 结构体、共用体和枚举
2.10.7.2 随机文件操作随机文件操作,即在文件中通过 C++相关的函数移动文件指针,并指向所要处理的字符 ( 字节 ) 。 随机文件提供在文件中来回移动文件指针和非顺序地读写文件的能力,这样在读写文件中的某一数据之前不需要再读写其前面的数据,从而能快速地检索,修改和删除文件中的信息 。
在 istream类中提供了 3个操作读指针的成员函数:
istream&istream::seekg (long pos);
istream&istream::seekg(long off,dir);
streampos istream::tellg();
其中,pos为文件指针的绝对位臵; off为文件指针的相对偏移量; dir为文件指针的参照位臵,其可能值为:
返回 277
2.10 结构体、共用体和枚举
cur=1 文件指针的当前位臵
beg=0 文件开头
end=2 文件尾
tellg()函数没有参数,它返回一个 long型值,用来表示从文件开始处到当前指针位臵之间的字节数 。
在 ostream类中同样提供了 3个操作写指针的成员函数:
ostream&istream::seekp (long pos);
ostream&istream::seekp(long off,dir);
streampos istream::tellp();
这 3个成员函数的含义与前面 3个操作读指针的成员函数相同,只不过它们是用来操作写指针的 。
返回 278
本章小结本章是 C++语言的基础,内容与 C语言多数一致 。
C++语言支持面向对象的程序设计 ( OOP),在面向对象的程序设计中,以,对象,为中心,并且将对象的属性和方法二者封装在一起,这种结合自然地反映了应用领域的模块性,因此具有相对稳定性 。 同时 OOP又引入了,类,( class) 的概念 。 类与类以层次结构组织,
属于某个类的对象除具有该类所描述的特性外,还继承了层次结构中该类上层所有类描述的全部性质,OOP方法的模块性与继承性,保证了新的应用程序设计可在原有对象的数据类型和功能的基础上,通过重用,扩展和细化来进行,而不必从头做起或复制原有代码,这样,
大大减少了重新编写新代码的工作量,同时降低了程序设计过程中出错的可能性,达到了事半功倍的效果 。
返回 279
本章小结一个 C++的程序是由函数构成的,程序中有且仅有一个 main函数,它总是从主函数 main开始运行 。 每个 C++的源程序要以,CPP作为程序存盘时的文件名后缀,源程序需要经过 C++编译系统的编译和连接,最后才能产生可运行的,EXE程序文件 。 C++源程序数据的输入和输出通常利用输入 /输出流对象 cin和 cout来完成,这时要求在程序的开头需要嵌入头文件 iostream.h。
程序的核心任务是对数据进行加工和处理,在 C++中任何数据是有类型的,不同的数据类型的关键字不同,
所占存储单元的大小不同,因而表示数的范围大小也不同 。 另外,根据数据在程序运行过程中是否发生变化将数据分为常量和变量,常量的值固定不变且数据类型是由用户在程序中的书写格式来决定,而变量则必须在程返回 280
本章小结中进行明确的定义,即定义其名称和类型,在程序中,
任何变量都要遵循先定义后使用的规则 。
C++为每种运算符规定了一个运算的优先级和结合特性,以控制各种运算的顺序,利用圆括号可以改变表达式的运算顺序 。 当在表达式中进行运算的数据类型不同时,C++将自动进行隐式转换,当然,用户也可利用强制类型转换的方法进行转换 。
利用程序的三种结构即:顺序结构,选择结构和循环结构可以实现对程序执行流程的控制 。 选择结构可使程序根据某个 ( 些 ) 条件是否成立,从而有选择的执行程序中的程序段,这可以利用 if语句实现 。 而循环结构可使某一段程序有条件地重复执行有限次,可利用 while,do-
while和 for语句实现,并且这些语句可以通过改变条件的形式进行相互转化 。
返回 281
本章小结数组是一个由若干相同类型的变量组成的集合,数组中特定的元素通过下标来访问,同一个数组中所有元素所占存储单元是连续的,整个数组所占存储单元的首地址就是数组中的第一个元素的地址,数组名本身代表了数组的首地址 。 当数组用于存放字符串时,由于字符串具有结束标记 ‘ \0?,所以在定义字符数组的大小时,要多定义一个元素 。
指针就是某一存储单元的地址,指针变量是专门存放其他变量指针的变量,当指针变量中存放了某一变量的地址时,则称该变量指向那个变量 。 因此,指针变量可以指向变量,数组,函数,字符串,结构体等 。 指针还可以作为函数的参数,以传递实参的地址 。
当程序代码量较大时,可根据功能的不同分成更小、
更容易管理的模块,这种模块就是函数。程序中所用的返回 282
本章小结函数有两类,一类是库函数,另一类是用户自定义函数,
库函数可直接使用,而用户自定义函数要先定义后使用 。
一个函数可定义成有参函数,也可定义成无参函数,当函数无返回值时,要把函数的类型定义成 void。 定义函数时,
函数名称后面括号内的参数是形式参数,形式参数可以是普通变量,数组名,指针变量,引用等 。 当发生函数调用时,实参与形参间发生了数据传递,要注意传值与传地址间的区别 。
内联函数是为了提高编程的效率而实现的,它适用于函数体代码较少且程序中不含有复杂程序结构的情况 。 函数重载允许用同一个函数名定义多个函数,系统会根据传递给函数的参数的数目,类型和顺序调用相匹配的函数,
函数重载使程序设计简单化 。
在函数定义中通过赋值运算可指定参数的默认值 。
返回 283
本章小结引用是 C++语言独有的特性,引用就是某一变量的别名,在定义时必须初始化,使用引用的主要目的是在函数参数传递过程中解决大对象的传递效率和空间不如意的问题。当利用引用作为函数的参数时,参数的传递过程中不产生值的副本。不允许声明引用数组,但可以用常量来初始化引用声明。当一个函数返回引用时,要注意局部对象返回的危险。
结构体是一种将不同数据类型的成员组织到一起的构造数据类型,因此,当定义结构体时,不产生内存的分配,
只有在定义了结构体的变量时,才分配内存单元 。 当结构体作为函数的参数进行传递时,其值进行了复制,因此,
当结构体很大时,宜采用结构体的引用传递函数参数 。 在使用结构体变量时,不能直接把它当成一个整体去使用,
返回 284
本章小结而只能访问和使用结构体中的成员 。 结构体取成员的方法是,结构体变量名,成员名,。 另外,在程序中可以定义结构体数组,也可以定义指向结构体的指针 。
利用 new运算符可以进行动态地分配内存,利用 delete
运算符可以释放已分配的内存 。
C++允许使用关键字 typedef为已有的数据类型定义新的名称,称为类型定义 。 类型定义只是为已有的数据类型生成一个别名,并不是定义了新的数据类型 。
数据文件的打开和关闭是通过使用 fstream类的成员函数 open和 close来实现的 。 fstream类是用来对文件流进行操作,它和标准输出输入流 ( cout,cin) 一起,是 C++实现流操作的最基本的类,而且它们有一个共同的基 类 ios。
为了能使用这些类的相关函数,还必须在程序中添上相关的包含文件 iostream.h和 fstream.h。