第二章 C++语言基础

第2章 C++语言基础
本章是学习C++语言的基础,包括以下几个方面:
1.结构化程序设计方法与面向对象程序设计方法的各自特点、
区别和相互联系。
2.面向对象的程序设计方法中的有关概念,如类、对象、封
装、继承、消息和多态性等。
3.C++程序的基本组成和框架结构。
4.掌握C++语言中的基本数据类型、各种运算符、表达式。
5.C++数据输入流对象cin和输出流对象cout的使用。
6.程序的3种基本结构
7.构造数据类型,如数组、结构体、指针等的定义方法、特
点和使用方法。
7.函数的定义、调用及函数调用过程中的参数传递的机理和
程序执行流程。
8.引用的概念及其定义和使用方法。
1
返回
2.1 从面向过程的程序设计到面向对象的程序设计
2.1.1 传统的结构化程序设计(Structured Programming--SP)方法
1.使用SP方法设计程序的步骤
数据声明
数据处理
结果输出
在数据处理过程中,采用的是自顶向下、分而治之的
方法,将整个程序按功能划分为几个可独立编程的子
过程模块,每一子模块完成指定的子任务,并且提供
一个清晰、严格的调用界面,主过程通过调用各子过
程完来成全部处理工作 。
返回
2
2.1 从面向过程的程序设计到面向对象的程序设计
2.SP方法的特点
优点:
(1)这种程序设计方法力求算法描述准确。
(2)对每一子过程模块容易进行程序正确性证明。
缺点:
(1)这种程序设计方法本质上是面向“过程”的,而
“过程”和“操作”又是不稳定和多变的,因此不能
直接反映人类求解问题的思路。
(2)程序代码可重用性差。程序中除少数标准库函数外,
每设计一个程序时,程序员几乎从零做起。即使重用
代码,通常也是通过拷贝或编辑重新生成一份。
(3)维护程序的一致性困难。该种方法将数据与对数据
进行处理的程序代码分离。
返回
3
2.1 从面向过程的程序设计到面向对象的程序设计
2.1.2 面向对象的程序设计(Object-Oriented Programming
----OOP)方法
1. 面向对象的有关概念
面向对象的程序设计方法强调直接以问题域(现实世
界)中的事物为中心来思考和认识问题,并按照这些
事物的本质特征把它们抽象为对象,以作为构成软件
系统的基础。
( 1 ) 对 象 ( Object ) : 每 个 对 象 都 具 有 属 性
(Attribute)和方法(Method)这两方面的特征。对
象的属性描述了对象的状态和特征,对象的方法说明
了对象的行为和功能,并且对象的属性值只应由这个
对象的方法来读取和修改,两者结合在一起就构成了
对象的完整描述。
返回
4
2.1 从面向过程的程序设计到面向对象的程序设计
(2)类(Class):具有相似属性和行为的一组对象,
就称为类。可见,有了类的概念以后,就可以对具有
共同特征的事物进行统一描述。
(3)封装(Encapsulation):封装把对象的属性和方
法看成了一个密不可分的整体,从而使对象能够完整
地描述并对应于一个具体事物 。
(4)继承(Inheritance):将客观事物进行归类是一
个逐步抽象的过程,反之,将类进行层层分类便是一
个概念逐渐细化的过程。
在面向对象的程序设计中,允许在已有类的基础上通过
增加新特征而派生出新的类,这称为继承。其原有的
类称为基类(base class),而新建立的类称为派生
类。
返回
5
2.1 从面向过程的程序设计到面向对象的程序设计
(5)消息(Message):在面向对象的程序设计中,由
于对象描述了客观实体,它们之间的联系通过对象间
的联系来反映。当一个对象需要另外一个对象提供服
务时,它向对方发出一个服务请求,而收到请求的对
象会响应这个请求并完成指定的服务。这种向对象发
出的服务请求就称为消息。
(6)多态性(Polymorphism):多态性是面向对象的另
一重要特征。在通过继承而派生出的一系列类中,可
能存在一些名称相同,但实现过程和功能不同的方法
(Method)。
所谓多态性是指当程序中的其他部分发出同样的消息
时,按照接收消息对象的不同能够自动执行类中相应
的方法。其好处是,用户不必知道某个对象所属的类
就可以执行多态行为,从而为程序设计带来更大方便。
返回
6
2.1 从面向过程的程序设计到面向对象的程序设计
2. 面向对象的程序设计方法(OOP方法)
这种方法将设计目标从模拟现实世界的行为转向了模
拟现实世界中存在的对象及其各自的行为。
在OOP中,将“对象”作为系统中最基本的运行实体,
整个程序即由各种不同类型的对象组成,各对象既是
一个独立的实体,又可通过消息相互作用,对象中的
方法决定要向哪个对象发消息、发什么消息以及收到
消息时如何进行处理等。
消息
数据
方法
消息
返回
7
2.1 从面向过程的程序设计到面向对象的程序设计
3.OOP方法的特点
(1)OOP以“对象”或“数据”为中心。由于对象自然地反映了应
用领域的模块性,因此具有相对稳定性,可以被用作一个组件去
构成更复杂的应用,又由于对象一般封装的是某一实际需求的各
种成分,因此,某一对象的改变对整个系统几乎没有影响。
(2)引入了“类”(class)的概念。类与类以层次结构组织,属
于某个类的对象除具有该类所描述的特性外,还具有层次结构中
该类上层所有类描述的全部性质,OOP中称这种机制为继承。
(3)OOP方法的模块性与继承性,保证了新的应用程序设计可在原
有对象的数据类型和功能的基础上通过重用、扩展和细化来进行,
而不必从头做起或复制原有代码,这样,大大减少了重新编写新
代码的工作量,同时降低了程序设计过程中出错的可能性,达到
了事半功倍的效果。
返回
8
2.1 从面向过程的程序设计到面向对象的程序设计
2.1.3 面向对象的程序设计方法与结构化程序设计方法
的比较
(1)传统的结构化程序设计方法以过程为中心构造应用
程序,数据和处理数据的过程代码是分离的、相互独
立的实体,设计出的程序可重用代码少,且当代码量
增加时维护数据和代码的一致性困难。
(2)面向对象程序设计方法中,对象所具有的封装性和
继承性使得代码重用成为可能,并大大减少了程序出
错的可能性。
(3)面向对象方法吸收了结构化程序设计方法的优点,
同时引入了新概念、新机制并建立了比传统方法更高
层次的抽象。
返回
9
2.2
C++程序的基本组成
2.2.1 从C语言到C++语言
C语言以其如下独有的特点风靡了全世界:
(1)语言简洁、紧凑,使用方便、灵活。C语言只有32
个关键字,程序书写形式自由。
(2)丰富的运算符和数据类型。
(3)可以直接访问内存地址,能进行位操作,使其能够
胜任开发操作系统的工作。
(4)生成的目标代码质量高,程序运行效率高。
(5)可移植性好。
返回
10
2.2
C++程序的基本组成
局限性:
(1)数据类型检查机制相对较弱,这使得程序中的一些
错误不能在编译阶段被发现。
(2)C本身几乎没有支持代码重用的语言结构,因此一个
程序员精心设计的程序,很难为其它程序所用。
(3)当程序的规模达到一定程度时,程序员很难控制程
序的复杂性。
根据执行效率、可扩展性、可维护性等要求进行编程语言
的取舍!
返回
11
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++语言。
返回
12
2.2
C++程序的基本组成
2.2.2 C++程序的结构与基本组成
一个简单的C++程序,是由若干个函数构成的,其中有
且仅有一个名称为main的函数存在,下图说明了C++程序
的基本框架结构:
#include<……>
声 :
明 函数声明
区 定义全局变量
主 类型 main(参数行)
程 {
序 程序主体;
区 }
返回
函 函数定义
数 {
定 函数主体;
义 }
区
13
2.2
C++程序的基本组成
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……等。
返回
14
2.2
C++程序的基本组成
2.主程序区
主程序以main()函数开始,是整个程序运行的入口,该函
数中可能包含的内容主要有:
(1)局部变量的声明:如:int i=1;
(2)函数调用:如:y=sin(x);
(3)一般运算:如:a=b+c+d/3;
(4)结构控制:如:if(a>b) c=a;
(5)对象与结构的处理。
(6)文件的处理等。
返回
15
2.2
C++程序的基本组成
3.函数定义区
程序中除了main函数之外,还可以包含其它的函数,
每个函数是由函数说明和函数体两部分构成的。如图2.3
所示:
函
数
定
义
区
函数说明
函数体
int max(int a,int b)
{
int c;
c=a+b;
return(c);
}
图2.3 C++函数的组成
4.程序举例
返回
16
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("printf is also can be used\n");
}
返回
17
2.2
C++程序的基本组成
上例程序结构可写为如下程序:
【例2-1】一个简单的C++程序。
// This is first C++ program
/* C语言的某些特征仍可沿用*/
#include "iostream.h"
#include "stdio.h"
void print(); //函数声明
void main()
{ int i;
char s[80];
返回
18
2.2
C++程序的基本组成
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");
}
返回
19
2.2
C++程序的基本组成
从上例可以看出:
(1)C语言中原有的规则和语句在C++中仍可继续使用,
但C++又增添了很多新的风格。
(2)一个C++的程序是由一到若干个函数构成的,但其
中必须有且仅有一个名称为main的函数存在。
(3)不管一个程序中有多个函数,只有main函数整个程
序运行时的入口,程序运行时从此函数开始执行。但在
程序中,main函数所处的位置可以任意。
(4)一个C++的函数是由两部分构成的,即函数的说明
部分和函数体,函数的说明部分包括了函数的返回值的
类型、函数的名称、圆括号、形参及形参的类型说明。
函数体由一对大括号{}括起来,其内容是由若干条语句
返回
20
2.2
C++程序的基本组成
构成,函数体的内容决定了该函数的功能。
(5)C++对程序中的名称是大小写“敏感”的,除特殊
情况下,应一律小写。
(6)程序中的注释:可以用/*…………*/或//(单行注
释)对程序中的内容进行注释。二者的区别在于,采用
/*…………*/方法时,注释可以写成多行,而采用//方法
时,注释只能写成一行,它可单独占一行,也可写在某行程
序代码的末尾。
(7)数据输出:除了使用printf( )函数,还可使用功能更
强大、更方便的cout对象进行输出数据。格式如下:
cout<<数据1<< 数据2<<……<< 数据n
如:上例中的语句cout<<s<<“ is ”<<i<<“ years old.”; 表
示同时输出了变量s的值、字符串“is”、变量i的值和字符
返回
21
2.2
C++程序的基本组成
串“years old.”
(8) 数据输入:除了使用scanf( )函数,还可使用功能
更强大、更方便的cin对象进行数据输入。格式如下:
cin>>变量1>>变量2>>……>>变量n
如:上例中的语句cin>>s;表示给变量s输入一个值
(9) 在分别使用cout和cin进行数据的输出和输入时,
需要在程序的开头嵌入”iostream.h”文件。在该头
文件中定义了输入输出流对象cout和cin等。
(10) 一个C++的源程序文件在存盘时,要以.CPP为文
件名后缀,而不是.C。
返回
22
2.3
C++数据类型、运算符和表达式
2.3.1 数据类型
(1)预定义数据类型(基本数据类型)。包括字符型、
整型、浮点型、无值型四种,其中浮点型又分为单精
度浮点型和双精度浮点型两种。
(2)构造数据类型,包括数组、结构体、共用体(联
合)、枚举、类等。
不要拘泥于具体的名称!
本节重点介绍C++的基本数据类型,有关构造数据
类型将在后面章节进行介绍。
返回
23
2.3
C++数据类型、运算符和表达式
2.3.1.1 基本数据类型
数据类型
关键字
字节数
字符型
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
无值型
数值范围
返回
24
2.3
C++数据类型、运算符和表达式
2.3.1.2 类型修饰符
C++还允许在基本数据类型(除void类型外)前加上类
型修饰符,来更具体地表示数据类型。C++的类型修饰
符包括:
signed
有符号
unsigned
无符号
short
短型
long
长型
返回
25
表2.2 C++的基本数据类型
数据类型标识符
字节数
数值范围
常量写法举例
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
signed int
4
unsigned int
4
-2147483648
2147483647
-2147483648
2147483647
0~4294967295
返回
~
1000
~
-123456
0xffff
26
表2.2 C++的基本数据类型
数据类型标识符
字节数
数值范围
常量写法举例
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
返回
27
2.3
C++数据类型、运算符和表达式
说明:
(1)表中带[ ]的部分表示是可以省略的,如short [int]可
以写为short int 或简写为short,二者的含义是相同的。
(2)四种修饰符都可以用来修饰整型和字符型。用signed
修饰的类型的值可以为正数或负数,用unsigned修饰的类
型的值只能为正数。
(3)用short修饰的类型,其值一定不大于对应的整数,
用long修饰的类型,其值一定不小于对应的整数。
返回
28
2.3
C++数据类型、运算符和表达式
2.3.1.3 常量
• 在C++语言中,数据分为常量和变量两大类。
• 由于程序中的数据是有类型的,所以常量和变
量都是有类型之分的。。
• 常量按照不同的数据类型可以分为: 字符型常
量、整型常量、浮点型常量,以及字符串常量
等。
• 程序是根据程序中常量的书写格式来区分它是
哪种类型常量的。
返回
29
2.3
C++数据类型、运算符和表达式
1.整型常量
在程序中书写整型常量时,没有小数部分。用户可根据
需要分别可以用十进制、八进制和十六进制的形式书写:
十进制格式 :由数字0至9和正、负号组成,书写时直
接写出数字,如:123,-516,+1000等。
八进制格式 :以数字0开头的数字(0至7)序列,
0111,010007,0177777等。
十六进制格式 :以0x或0X开头的数字(数字0至9、字
母a至z)序列,如0x78AC,0xFFFF等。
返回
30
2.3
C++数据类型、运算符和表达式
2.浮点型常量
只能用十进制来表示。可以用小数或指数形式表示,不分
单精度和双精度类型。如:34.5 , .345, 1.5e-3
3.字符型常量
(1)用一对单引号括起来的一个字符,单引号只是字
符与其他部分的分割符,不是字符的一部分,并且,不能
用双引号代替单引号。在单引号中的字符不能是单引号或
反斜杠。如:
a’ , ‘A’, ‘#’ 合法的字符常量
‘’’ , ‘\’
非法的字符常量
“A”
不代表字符常量
(2)另一种表示字符常量的方法是使用转义字符。
C++规定,采用反斜杠后跟一个字母来代表一个控制字符,
具有新的含义 。
31
返回
2.3
C++数据类型、运算符和表达式
C++中常用的转义字符
转义字符
\a
\b
\n
\r
\t
\v
\\
\’
\”
\0
\ddd
\xhh
含义
响铃(BEL)
退格(BS)
换行(LF)
回车(CR)
水平制表(HT)
垂直制表(VT)
反斜杠
单引号
双引号
空格符(NULL)
任意字符
任意字符
返回
ASCII码值(十进制)
7
8
10
13
9
11
92
39
34
0
3位八进制数
2位十六进制数
32
2.3
C++数据类型、运算符和表达式
4.字符串常量
用一对双引号括起来的一个或多个字符的序列称为字
符串常量或字符串。字符串以双引号为定界符,双引号不
作为字符串的一部分。如:
“Hello”, “Good Morning!” ,“I say:
\“ Goodbye!\””
字符串中的字符数称为该字符串的长度,在存储时,
系统自动在字符串的末尾加以字符串结束标志,即转义字
符 ‘\0’。
5.符号常量
常量也可用一个标识符来代表,称为符号常量。如:
#define PRICE 30
main()
{……}
返回
33
2.3
C++数据类型、运算符和表达式
使用符号常量应注意以下几个方面:
(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;
返回
34
2.3
C++数据类型、运算符和表达式
(2)利用#define定义宏常量
一般格式: #define 宏名 常数
如:#define PI 3.14
…………
s=2*PI*r;
…………
(3)利用const定义正规常数
一般格式:const 数据类型标识符 常数名=常量值;
说明:
① const必须放在被修饰类型符和类型名前面
② 数据类型是一个可选项,用来指定常数值的数据类型,
如果省略了该数据类型,那么编译程序认为它是 int 类型
返回
35
2.3
C++数据类型、运算符和表达式
如:const int a=10; 表示定义了一个初始值为10的整型常
量,它在程序中不可改变,但可用于表达式的计算中,
2.3.1.4 变量
1.变量的概念及特点
每一变量就相当于一个容器,对应着计算机内存中的某
一块存储单元,用于存储程序中的数据。变量的值具有以
下两个特点:
(1)“一充即无”:即将一个新数据存放到一个变量中
时,该变量中原来的值消失,变量的值变成了新值。
如:执行完语句int i; i=10; i=20;后i的值为20,而不是10。
返回
36
2.3
C++数据类型、运算符和表达式
(2)“取之不尽”:可将某个变量的值与程序中的其它
数据进行各种运算,在运算过程中,如果没有改变该变
量的值时,那么,不管用该变量的值进行多少次运算,
其值始终保持不变。
如:语句int i,j,k; i=10; j=i+10; k=i+j*5;其中,i的值可无
限制地多次使用,但它的值始终保持值10,因为在程序
中没有改变变量i的值。
2.定义变量
程序中的每一变量,都要先定义,后使用。
定义变量的一般有以下三种格式:
数据类型标识符 变量名;
数据类型标识符 变量名=初始化值;
返回
37
2.3
C++数据类型、运算符和表达式
数据类型标识符 变量名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++中区分变量名的大小写。
返回
38
2.3
C++数据类型、运算符和表达式
(4)变量名不能和C++中的关键字同名,也不能和用户
编制的函数或C++库函数同名。如:int, double或static都
不能作为变量名。
(5)变量名尽量做到“见名知意”。
3.定义变量的位置
在程序中的不同位置采用不同的变量定义方式,决定
了该变量具有不同的特点。变量的定义一般可有以下三
种位置:
(1)在函数体内部
在函数体内部定义的变量称为局部变量,这种局部变
量只在进入定义它的函数体时起作用,离开该函数体后
该变量就消失(被释放),即不再起作用。因此,不同
函数体内部可以定义相同名称的变量,而互不干扰。如:
返回
39
2.3
C++数据类型、运算符和表达式
void func1(void)
{ int y;
y=2;
}
void func2(void)
{ int y;
y=-100;
}
在本例中,函数func1和func2的函数体内部都分别定义
了变量y,但它们都只能在各自的函数体内起作用,都是
局部变量。
返回
40
2.3
C++数据类型、运算符和表达式
(2)形式参数
当定义一个有参函数时,函数名后面括号内的变量,统称为形式
参数。如:
int is_in(char *a, char b)
{ while(*a)
if (*a==b)
return 1;
else
a++;
return 0;
}
本例中,函数名is_in后面括号内的变量a和b是该函数的形式参数,
它们都只能在该函数体内起作用,是该函数的局部变量。
返回
41
2.3
C++数据类型、运算符和表达式
(3)全局变量:在所有函数体外部定义的变量,其作用
范围是整个程序,并在整个程序运行期间有效。如:
#include “stdio.h”
int count;
//定义count变量是全局变量
void func1(void);
void func2(void);
int main()
{ count=10;
func1();
return 0; }
返回
42
2.3
C++数据类型、运算符和表达式
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(‘.’);
}
返回
43
2.3
C++数据类型、运算符和表达式
2.3.2 运算符和表达式
程序中对数据进行的各种运算是由运算符来决定的,
不同运算符的运算方法和特点是不同的,从此可以看
出,一个运算式子中要涉及到数据及运算符,而运算
符是对数据进行指定操作,并产生新值的特殊符号。
2.3.2.1 算术运算符和算术表达式
算术运算符就是对数据进行算术运算,如:加、减、
乘、除等,是在程序中使用最多的一种运算符,C++
的算术运算符如表2.4所示。
返回
44
表2.4 C++的算术运算符
运算符
功能
数据类型
例子
-
负号
数值
x=-y;
+
加
数值
z=x+y;
-
减
数值
z=x-y;
*
乘
数值
z=x*y
/
除
数值
z=x/y;
%
求余
整数
z=x%y
++
自加
数值
z++或++z
--
自减
数值
z--或--z
算术表达式是指由算术运算符、括号将常量、变量、函
数、圆括号等连接形成的一个有意义的式子。如:
返回
45
2.3
C++数据类型、运算符和表达式
(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++提供的对
应的数学运算库函数来代替。
返回
46
2.3
C++数据类型、运算符和表达式
③ 要特别注意表达式中两个整型数相除的情况。如:
有一数学表达式为2/3(f-32),要写成对应的C++的表达
式时,正确地写法应写2.0/3.0*(f-32)。而不是2/3*(f-32)
2.3.2.2 赋值运算符和赋值表达式
赋值运算符的功能将某个数据的值赋给某个变量。
赋值运算符的用法格式:
变量名 赋值运算符 常量、变量或表达式
说明:
(1)被赋值的目标,即赋值运算符左边的量必须是变
量,而不能是常量或表达式。
返回
47
2.3
C++数据类型、运算符和表达式
(2)C++中的赋值运算符如表2.5所示。
赋值运算符
=
+=
-=
*=
/=
%=
例子
x=x+y
x+=y+z
x-=y+z
x*=y+z
x/=y+z
x%=y+z
等价形式
x=x+y
x=x+(y+z)
x=x-(y+z)
x=x*(y+z)
x=x/(y+z)
x=x%(y+z)
(3)要注意区分赋值运算符“=”与数学上的“等号”
间的区别,如:
int x,y;
//定义变量x,y为int类型变量
x=10;
//将变量x赋成值10
返回
48
2.3
C++数据类型、运算符和表达式
x=x+20;
//将x的值在原值(10)的基础上再加上值20后
(结果为30)赋给变量x
y=x++
//将x的值赋给变量y(值为30),变量x再自加1
y-=x+5;
// 等 价 于 y=y-(x+5) ;右 边 表 达 式 的 值 为 30(31+5)=-6,y被赋成值-6
x%=y+10; // 等 价 于 x=x%(y+10) ; 右 边 表 达 式 的 值 为
31%(-6+10)=3,x被赋成值3
2.3.2.3 sizeof运算符
sizeof运算符功能是求某一数据类型或某一变量在内存
中所占空间的字节数。其使用的一般形式:
sizeof(变量名或数据类型)或sizeof 变量名或数据类型
返回
49
2.3
C++数据类型、运算符和表达式
2.3.2.4 关系运算符和关系表达式
关系运算符就是对两个量之间进行比较的运算符,如
表2.6所示。
返回
50
2.3
C++数据类型、运算符和表达式
关系运算符
<
<=
>
>=
==
!=
含义
小于
小于或等于
大于
大于或等于
等于
不等于
例子
i>10
(x+y)*2<=100
x+y>z
x-y>=a*b+2
x+y==a+b
x-y!=0
由关系运算符将两个表达式连接形成的运算式子是关系表达式,
一个关系表达式的值是一个逻辑值,当为真时,值为1,为假时,值
为0。
如:假设a=1,b=20,c=3,则
a<b
表达式成立,其值为1
b==c
表达式不成立,其值为0
(a+b)!=c表达式成立,其值为1
返回
51
2.3
C++数据类型、运算符和表达式
注意:
在对两个表达式的值进行是否相等的比较时,要用运算符
“==”,而不能写成“=”。如:if(x=y)隐蔽!
2.3.2.5 逻辑运算符和逻辑表达式
逻辑运算符是对两个逻辑量间进行运算的运算符,如表
2.7所示。
逻辑运算符
含义
例子
!
逻辑非
!(x>10)
&&
逻辑与
(i>1) && (i<10)
||
逻辑或
c==0 || c==9
返回
52
2.3 C++数据类型、运算符和表达式
由逻辑运算符将两个表达式连接形成的式子叫逻辑
表达式。各种逻辑运算的“真值表”如表2.8所示。对
于参加逻辑运算的操作数,系统认为“非0”为真,“0”
为假。而逻辑表达式的结果只能为逻辑真(1)或逻辑
假(0)。
表2.8 逻辑运算真值表
a
b
a&&b
a||b
!a
!b
真
真
真
真
假
假
真
假
假
真
假
真
假
真
假
真
真
假
假
假
假
假
真
真
返回
53
2.3
C++数据类型、运算符和表达式
注意:
(1)C或C++中在给出一个逻辑表达式的最终计算结果
值时,用1表示真,用0表示假。但在进行逻辑运算的过
程中,凡是遇到非零值时就当真值参加运算,遇到0值时
就当假值参加运算。如:int a=10,b=15,c=14; 则(a+6)
&& (b>c)的值为1(真)。
(2)在逻辑表达式的求值过程中,并不是所有的逻辑运
算符都被执行,只是在必须执行下一个逻辑运算符才能
求出表达式的值时,才执行该运算符。
见教材P43.
返回
54
2.3
C++数据类型、运算符和表达式
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所示。
返回
55
2.3
C++数据类型、运算符和表达式
运算符
&
|
^
~
<<
>>
含义
按位与
按位或
按位异或
按位取反
按位左移
按位右移
例子
i&128
j|64
j^12
~j
i<<2
j>>2
位运算的运算规则为:
(1)按位与&:两个运算量相应的位都是1,则该位的结
果值为1,否则为0;
(2)按位或|:两个运算量相应的位只要有一个是1,则
该位的结果值为1,否则为0;
返回
56
2.3
C++数据类型、运算符和表达式
(3)按位异或^:两个运算量相应的位不同,则该位的
结果值为1,否则为0;
(4)按位取反~:将运算量的每一位取反。
(5)按位左移<<:将操作数中的每一位向左移动指定的
位数,移出的位被舍弃,空出的位补0。
(6)按位右移>>:将操作数中的每一位向右移动指定的
位数,移出的位被舍弃,空出的位补0或补符号位。
如:a=5,b=6,则:
a
b
00000101
&00000110
00000100
00000101
|00000110
00000111
00000101
^ 00000110
00000011
~ 00000110
11111001
即:a&b=4,a|b=7,a^b=3,~b=249。
返回
57
2.3
C++数据类型、运算符和表达式
2.复合位运算符
位运算符与赋值运算符结合可以形成复合位运算符,
如表2.10所示。
运算符
例子
等价形式
&=
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.2.8 强制类型转换运算符
该运算符的功能是将某一数据从一种数据类型向另一
返回
58
2.3
C++数据类型、运算符和表达式
种数据类型进行转换。其使用的一般形式:
数据类型标识符 (表达式)
(数据类型标识符)表达式
如:int i=2;
float a,b;
a=float(i); //将变量i的类型强制转换为浮点型,并将
其值赋给变量a
b=(float)i; //将变量i的类型强制转换为浮点型,并将
其值赋给变量b
2.3.2.9 逗号运算符
逗号运算符的运算优先级是最低的。一般形式为:
表达式1,表达式2,……,表达式N
返回
59
2.3
C++数据类型、运算符和表达式
在计算逗号表达式的值时,按从左至右的顺序依次分
别计算各个表达式的值,而整个逗号表达式的值和类型
是由最右边的表达式决定。
如:有语句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所示。
返回
60
表2.11 C++中运算符的优先级和结合性
优先级
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
运算符
() :: [] -> . .* ->*
! ~ ++ -- + - * & (类型) sizeof new[] delete[]
* / %
+ << >>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %= <<= >>= &= ^= |=
,
返回
结合性
自左至右
自右至左
自左至右
自左至右
自左至右
自左至右
自左至右
自左至右
自左至右
自左至右
自左至右
自左至右
自右至左
自右至左
自左至右
61
2.4 数据的输入与输出
在C++语言中,数据的输入和结果的输出是分别使用
系统所提供的输入流对象cin和输出流对象cout来完成的。
在使用过程中,只要在程序的开头嵌入相应的头文件
“iostream.h”即可。
2.4.1 数据的输出cout
输出流对象输出数据的语句格式为:
cout<<数据1<<数据2<<……<<数据n;
说明:
(1)cout是系统预定义的一个标准输出设备(一般代表
显示器);“<<”是输出操作符,用于向cout输出流中插
入数据。
(2)cout的作用是向标准输出设备上输出数据,被输出
的数据可以是常量、已有值的变量或是一个表达式。
返回
62
2.4 数据的输入与输出
如:
#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;
返回
63
2.4 数据的输入与输出
表示输出完字符串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语句也可拆成若干行书写,但注意语句结
束符“;”只能写在最后一行上。如:对于上面的语句也
可写成如下形式:
返回
64
2.4 数据的输入与输出
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. ";
返回
65
2.4 数据的输入与输出
(7)在cout中还可以使用流控制符控制数据的输出格式,
但使用这些流控制符时,要在程序的头上嵌入头文件
#include <iomanip.h>。常用的流控制符及其功能如表2.12
所示。
表2.12 I/O流的常用控制符
控制符
dec
hex
oct
setfill(c)
setprecision(n)
setw(n)
setiosflags(ios::fixed)
功能
十进制数输出
十六进制数输出
八进制数输出
在给定的输出域宽度内填充字符c
设显示小数精度为n位
设域宽为n个字符
固定的浮点显示
返回
66
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;
返回
67
2.4 数据的输入与输出
① 设置域宽:所谓域宽就是被输出数据所占的输出宽度
(单位是字符数)。设置域宽可以使用流控制符setw(n)
和cout的方法cout.width(n)
其中n为正整数,表示域宽。但是, cout.width(n)和
setw(n)二者都只对下一个被输出的数据有作用,若一
个输出语句内有多个被输出的数据,而要保持一定格
式域宽时,需要在每一输出数据前加上cout.width(n)或
setw(n)。
此外,当参数n的值比实际被输出数据的宽度大时,
则在给定的域宽内,数据靠右输出,不足部分自动填
充空格符;若被输出数据的实际宽度比n值大时,则数
据所占的实际位数输出数据,设置域宽的参数n不再起
作用。
返回
68
2.4 数据的输入与输出
【例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的输出结果
返回
69
2.4 数据的输入与输出
② 设置域内填充字符:在默认情况下,当被输出的数据
未占满域宽时,会自动在域内靠左边填充相应个数的空
格符。但我们也可以设置在域内填充其他的字符,方法
是利用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;
返回
70
2.5 C++的控制语句
2.5.1 C++语句概述
语句(statement)是程序中最小的可执行单位。一条语
句可以完成一种基本操作,若干条语句组合在一起就能
实现某种特定的功能。C++中语句可以分为以下三种形式:
1. 单一语句
在任何一个表达式后面加上分号(;)就构成了一条
简单的C++语句,例如:
c=a+b;
b++;
a>b?a:b;
cout<<“Hello C++”<<endl;等等。
返回
71
2.5 C++的控制语句
2. 空语句
仅由单个分号构成的语句,即
;
称为空语句。
空语句不进行任何操作。该语句被用在从语法上需要
一条语句,但实际上却又不进行任何操作的地方。
3.复合语句
复合语句是用一对花括号{ }括起来的语句块。复合语
句在语法上等效于一个单一语句。
使用复合语句应注意:
(1) 花括号必须配对使用;
(2) 花括号外不要加分号。
返回
72
2.5 C++的控制语句
2.5.2 C++程序的三种基本结构
在程序设计中,语句可以按照结构化程序设计的思想
构成三种基本结构,它们分别是顺序结构、分支结构和
循环结构,如图2.5所示。
语句A
语句B
顺序结构
条件
P
语句A
语句B
分支结构
条件
P真
语句A
假
循环结构
图2.5 程序的三种基本结构
返回
73
2.5 C++的控制语句
1.顺序结构
程序按照语句的书写顺序依次执行,语句在前的先执行,
语句在后的后执行,只能满足设计简单程序的要求。
2. 分支结构
在分支结构中,程序根据判断条件是否成立,来选择执
行不同的程序段。也就是说,这种程序结构,能有选择地
执行程序中的不同程序段。
3. 循环结构
在循环结构中,程序根据判断条件是否成立,来决定是
否重复执行某个程序段。
程序的执行流程和顺序是由程序中的控制语句来完成的,
而控制流程的主要方式是分支和循环。
返回
74
2.5 C++的控制语句
2.5.3 if 语句
if语句是最常用的一种分支语句,也称为条件语句。if
语句有三种形式:单分支if 语句、双分支if语句和多分支
if语句,如图2.6所示。
表达式
假
真
语句
真
表达
式
语句1
单分支if 语句
假
语句2
双分支if语句
返回
75
2.5 C++的控制语句
表达式
1
假
真
假
表达式
2
假
真
语句1
真
语句3
语句2
语句4
多分支if语句
2.5.3.1 单分支if 语句
if(表达式)
语句
返回
76
2.5 C++的控制语句
其执行过程为:先计算关键字if后面的表达式的值,若为
真,则执行if后的“语句”部分 ,否则跳过该“语句”部
分。不管是否执行“语句”部分,最后都要接着“语句”
部分的后面,继续执行程序的其它部分。
注意:
(1)括号不能省略。
(2)在if(表达式)后不能加分号“;”。
(3)关键字if的后面的表达式可以是任意的表达式,只
要表达式的值为非0,即当真值处理,否则当假值处理。
(4)if语句的内嵌语句可以是单一语句,也可以是复合
语句。
(5)尽量使if语句的内嵌语句比if语句缩进,这是良好编
程书写风格。
返回
77
2.5 C++的控制语句
如: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
返回
78
2.5 C++的控制语句
其执行过程为:先判断表达式的值,若为真,则执行
语句块1,否则执行语句块2。不管程序执行语句块1还是
执行语句块2,最后都要跳到语句块2的后面接着执行程
序中后面的语句。
注意:
(1)语句块1、语句块2既可以是单一语句也可以是用{}
括起来的复合语句。
(2)else子句必须与if子句配对使用,不能单独使用。
(3)else子句必须处在if子句的后面,且else语句总是和
离它最近的前面未配对的if语句配对。
【例2-6】输入一个年号,判断是否为闰年,如果是则输
出“yes”,否则输出“Not”。
分析:只要满足下列两个条件之一者,即是闰年。
返回
79
2.5 C++的控制语句
① 年号能被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程序运行结束";}
返回
80
2.5 C++的控制语句
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
返回
81
2.5 C++的控制语句
【例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!";
返回
82
2.5 C++的控制语句
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语句
可以更方便、更简洁地实现多分支结构。
返回
83
2.5 C++的控制语句
switch语句的一般形式为:
switch(表达式)
{ case 常数1:语句1;break;
case 常数2:语句2;break;
………………
case 常数n:语句n;break;
default: 语句n+1
}
switch语句的执行过程是:
① 计算switch语句后面的表达式的值,当表达式的值与某
一个case后面的常量的值相等时,就执行此case后面的语
句,若所有的case中的常量的值都没有与表达式的值相匹
返回
84
2.5 C++的控制语句
配的,就执行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()
返回
85
2.5 C++的控制语句
{ 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!"; }
}
返回
86
2.5 C++的控制语句
说明:
① 常数1~常数n必须互不相同,且每一常数后面要有冒号
“:”;
② 各case子句和default子句的次序可任意;
③ 语句1~语句n+1可以为复合语句;
④ 在switch语句中出现的break语句并不是必需的,这要根
据程序的需要来决定。在此break语句的作用是跳出switch
语句;
⑤ 各case子句后面必须是常数,而不能是变量或表达式
2.5.5 循环语句
C++提供了三种循环结构:while循环语句、do-while循
环语句和for循环语句。
返回
87
2.5 C++的控制语句
2.5.5.1 while循环语句
while语句的一般形为:
while(表达式)
{循环体语句}
该语句的执行过程:首先判断while后面的表达式
的值,若表达式的值为真,则执行while的内嵌语句
(即循环体)一次;然后重复以上过程,直到表达式
的值为假时,才退出循环,接着执行循环体语句后面
的其它程序语句。
100
【例2-9】 求  n
n 1
返回
88
2.5 C++的控制语句
#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语句的一般形式为:
返回
89
2.5 C++的控制语句
do
{
循环体语句
} while(表达式);
该语句的执行过程:首先执行do-while的内嵌语句(循
环体语句)一次,然后再判断while后面的表达式的值,
若表达式的值为真,则重复执行do-while的内嵌语句,如
此反复,直到表达式的值为假时,循环结束,执行while
后面的语句。 100
【例2-10】 求  n
n 1
#include<iostream.h>
void main()
返回
90
2.5 C++的控制语句
{ 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语句则一次都不执行。
返回
91
2.5 C++的控制语句
2.5.5.3 for循环语句
for循环语句的一般格式为:
for(表达式1;表达式2;表达式3)
{ 循环体语句 }
该语句的执行过程是:
① 执行for后面的表达式1;
② 执行表达式2,若表达式2的值为真,则执行for语句的
内嵌语句(即循环体语句),然后执行第③步,若为假,
则循环结束,执行第⑤步;
③ 执行表达式3;
④ 返回继续执行第②步;
⑤ 循环结束,执行for语句的循环体下面的语句。
返回
92
2.5 C++的控制语句
100
n
【例2-11】 求 
。用for语句实现循环。
n 1
#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++的三种循环语句可以相互嵌套,构成循环
返回
93
2.5 C++的控制语句
嵌套。以下几种都是合法的循环嵌套:
(2)while()
(1)for(;;)
{
{
……
……
for(;;)
for(;;)
{
}
{
}
do{
……
……
}
}while( );
……
}
返回
94
2.5 C++的控制语句
(3)do{
……
for(;;)
{
}
……
}while( );
同样,if语句和switch语句也可以与这三种语句嵌套使用。
注意:
(1)循环嵌套时,外层循环和内层循环间是包含关系,
即内层循环必须被完全包含在外层循环中,不得交叉。
(2)当程序中出现循环嵌套时,这时,程序每执行一次
外层循环,则其内层循环必须循环所有的次数(即内层
返回
95
2.5 C++的控制语句
循环结束)后,才能进入到外层循环的下一次循环。
2.5.5.5 限定转向语句
C++提供了跳转语句break和继续语句continue。
1. break语句
break语句的一般形式为:
break;
该语句只能用于两种情况:
(1)用在switch结构中,当某个case子句执行完后,使用
break语句跳出switch结构。
(2)用在循环结构中,用break语句来结束循环。如果在
嵌套循环中,break语句只能结束其所在的那层循环。
返回
96
2.5 C++的控制语句
【例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;
返回
97
2.5 C++的控制语句
sum+=n; }
cout<<"sum="<<sum<<endl;
}
2.continue语句
continue语句的一般形式为:
continue;
该语句只能用在循环结构中。当在循环结构中遇到
continue语句时,则跳过continue语句后的其他语句结束本
次循环,并转去判断循环控制条件,以决定是否进行下一
次循环。
【例2-13】 输出0~100之间所有不能被3整除的数。
返回
98
2.5 C++的控制语句
#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语句是先执行循环体,后判断条件;
返回
99
2.5 C++的控制语句
(3)for语句功能最强,可完全取代while和do-while语句;
(4)while和do-while语句中循环变量初始化应该在循环前
提前完成,并在while后指定循环条件,循环体中要包含使
循环趋于结束的语句,而for循环可把这些操作放在for语句
当中。
2.6 数组及其使用
前面已经讲过基本数据类型, 如:整型,字符型,实型等,
C++语言还提供了构造数据类型,如:数组、结构体、联合体
等,有的书中也叫”导出数据类型”,本节先介绍数组。
数组是由若干相同数据类型的数据所组成的有序集合。
数组中每一个数据又称为数组元素,它们之间具有固定的
先后顺序。用一个统一的数组名和下标来唯一地确定数组
中的元素。
返回
100
2.6 数组及其使用
凡是具有一个下标的数组称为一维数组,具有两个或
两个以上下标的数组称为多维数组。
2.6.1 一维数组
2.6.1.1 一维数组的定义
一维数组定义的一般格式为:
类型说明标识符 数组名[常量表达式];
如: int b[5];
对定义作几点说明:
(1)数组名的命名遵循C++语言标识符的命名规则;
(2)数组名后边是用[ ]括起来的常量表达式,而不能用
圆括号。
返回
101
2.6 数组及其使用
(3)常量表达式表明该数组的长度,即数组中元素的个
数。如:int b[5];表示b数组中共有5个元素。
(4)常量表达式中可以包括常量和符号常量,不能为变量,
即不允许对数组的大小作动态定义。如以下定义不正确:
int n;
scanf(“%d”,&n);
int a[n];
2.6.1.2 一维数组的引用
一维数组中各元素在内存中所占的存储单元按下标序
号顺序存放,C++语言规定,只能逐个引用数组中的元素,
而不能一次引用整个数组,而数组元素的表示形式为:
数组名[下标]
返回
102
2.6 数组及其使用
【例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;
}
返回
103
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。
返回
104
2.6 数组及其使用
(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列)的数组。
返回
105
2.6 数组及其使用
注意:不能写成 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]等
返回
106
2.6 数组及其使用
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}};
这种赋值方法比较直观,把第一对括号内的数值赋给
第一行的元素,第二括号内的数值赋给第二行的元素,
依此类推。
返回
107
2.6 数组及其使用
(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};
也可以只对部分元素初始化而省略第一维的长度,但应
返回
108
2.6 数组及其使用
分行进行初始化,如:
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.字符和字符串结束标志:
返回
109
2.6 数组及其使用
在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."
返回
110
2.6 数组及其使用
(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.字符串的输入:
除了可以在程序中利用字符数组初始化的方法或赋值
方法将字符串存放到字符数组外,还可以采用以下方法,
但要注意,只能用字符数组接收输入的字符串。
返回
111
2.6 数组及其使用
(1)利用cin直接输入。格式是:
cin>>字符数组名;
如:
#include <iostream.h>
void main()
{ char s[20];
cin>>s;
cout<<s; }
当程序运行时,输入abcde并回车时,则输出结果为
abcde,但当输入ab cde时,输出结果为ab。因此,这种方
法输入字符串时,cin只能接收空格符之前的部分。无法
完成接收全部的字符串。
返回
112
2.6 数组及其使用
(2)利用cin流对象的getline方法。格式是:
cin.getline(字符数组名,输入字符串的最大长度n);
其中:
① 参数“字符数组名”是存放字符串的数组名称;
② 参数“输入字符串的最大长度n”包括字符串结束标记
\0在内。如:
#include <iostream.h>
void main()
{ char s[20];
cin.getline (s,20);
cout<<s; }
返回
113
2.6 数组及其使用
当程序运行过程中输入abcdef并回车时,程序的输出
结果为abcdef。而当输入ab cdef回车时,程序的输出结果
为ab cdef。由此可见,该种方法可以接收含有空格符的
字符串。
(3)利用cin流对象的get方法。格式是:
格式1:cin.get(字符数组名,输入字符串的最大长度n);
格式2:[字符变量名=]cin.get();
说明:
① 格式1中的两参数的含义同getline方法。
② 格式2表示输入一个字符,如果要保存该字符,则在其
左边写上被赋值的变量名和赋值号,如果不保存该字符,
则可写为cin.get();
返回
114
2.6 数组及其使用
#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间的区别。
返回
115
2.7 函数
一个C++程序是由若干个源程序文件构成的,而一个
源程序文件是由若干个函数构成。
从用户的角度看,有两种不同的函数:库函数和用户
自定义函数。所谓库函数也称标准函数,由C++系统提供。
而用户自定义函数则需要用户先定义,后使用。
2.7.1 函数的定义
2.7.1.1 函数的定义格式
定义函数的一般形式:
函数返回值的数据类型标识符
{函数体}
函数名(形式参数表及其类型)
返回
116
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";
}
返回
117
2.7 函数
在C++中定义函数时注意:
(1)函数的形参及类型说明要采用新的ANSI标准,即
必须放在函数名后面的括号内。
(2)当形参有多个时,必须用逗号隔开。
(3)如果函数是无参函数,括号也不能省略。
(4)所有的函数都要先定义,后使用(调用)。
(5)不能省略函数值的类型,必须表明该函数的函数
值的类型,即使该函数没有返回值,也要注明函数值
的类型为void。
返回
118
2.7 函数
2.7.1.2 函数的参数和函数的返回值;
所谓调用函数是指在程序中使用了该函数。
主调函数
被调函数
调用点
1.形式参数和实际参数(形参和实参)
在调用函数时,大多数情况下,主调函数和被调函数
之间有数据传递关系。而函数之间的数据传递就是靠函
数的参数进行的,而对无参函数的调用,没有数据传递
返回
119
2.7 函数
在定义函数时,函数名后面括号内的变量名为“形式
参数”(形参)。在调用函数时,函数名后面括号内的表
达式为“实际参数”(实参)。
例: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=a>y?x:ty;
return(z); }
返回
120
2.7 函数
关于形参和实参说明几点:
(1)实参可以是变量、常量、或表达式,但必须有确定
的值。而形参必须是变量。
(2) 形参变量,只有存在发生函数调用时,形参才被分
配存储单元,在调用结束时,形参所占的内存单元被释
放。
(3)实参与形参的类型必须一致,否则会发生“类型不
匹配”的错误。
(4)实参对形参的数据传递是“值传递”,即单向传递。
由实参把数据传给形参,并且存储单元与形参是不同的
单元,并将实参对应的值依次传递给形参变量。调用结
束后,形参单元被释放,而实参单元保留并维持原值。
返回
121
2.7 函数
2. 函数的返回值:
(1)函数的返回值是通过函数中的return语句获得的,
return语句的格式为:
return(表达式);或return 表达式;
return语句的功能有两个,
(A) 强制程序执行的流程从被调函数返回到主调函数
(B) 给主调函数带回一个确定的函数值
如:int max(int a,int b)
{ return(a>b?a:b); }
返回
122
2.7 函数
(2) 函数值的类型:函数返回值的类型就是在定义函
数时的函数值的类型。在定义函数时,函数值说明的类
型和return语句中的表达式类型不一致时,则以函数类型
为准。
(3)如果被调用函数中没有return语句,为了明确表示
函数“不返回值”,要用viod定义无类型。
如: viod print()
{ printf(“c language”);
}
这样系统就保证不使函数带回任何值。
返回
123
2.7 函数
2.7.2 函数的调用
1.函数调用的格式
函数名(实参数)
如果调用的是无参函数,则实参表可略去,但函数的括
号不能省.
如果实参表中有多个参数,之间用逗号隔开,实参的
类型、个数应与形参顺序一一对应。
函数通过下列三种方式完成函数调用:
(1)函数调用语句:即以一个函数的调用后面加上“;”
作为一个语句。如:printf();
(2)函数表达式:即函数出现在一个表达式中,这时要
求 函 数带回一个 确定的值以参加表达式的运算 。如:
c=2*max(a,b);
124
返回
2.7 函数
(3)函数参数:以函数的调用作为一个函数的实参。 如:
M=max(a,max(b,c));
2.调用函数时的前提条件
在一个函数中调用另一个函数,需要具备的条件:
(1)首先被调用的函数必须已经存在的函数。如果调用库
函数,一般还应在本文件的开头用#include命令将调用有关
库函数时所需用到的信息包含到本文件来。
(2)如果调用用户自己定义的函数,则必须对被调函数的
原型进行说明,函数的原型包括:
函数值的类型标识符 被调用函数名(形参及其类型表);
(3)对函数原型的说明,通常放在程序的顶部,也可以存
放到一个头文件中,然后利用#include 语句嵌入到程序中。
返回
125
2.7 函数
3.函数的定义与函数调用间的区别
(1)函数的“定义”是一个函数功能的确立,包括指定
函数名,函数返回值的类型,形参及其类型,函数体等,
它是一个完整的、独立的函数单位。
(2)函数的“说明”则只是对已经定义好的函数的返回
值进行类型的说明,它包括函数名,函数类型和一对括
号。而不包括形参和函数体。
(3)对函数进行说明的作用是告诉系统,在本程序中将
要用到的函数是什么类型,以便在主调函数中按此类型
对函数值作相应的处理。
返回
126
2.7 函数
2.7.3 函数的嵌套调用
C++语言中函数的定义是平行的、独立的,所以,函
数的定义是不能嵌套进行的,但函数的调用可以。嵌套
调用即在调用一个函数的过程中,又调用另一函数。
main()函数
{
a( )函数
b( )函数
{
{
……
……
……
调用a函数
调用b函数
……
……
……
}
}
}
返回
127
2.7 函数
在本例中,main函数在执行过程中,调用了函数a,而
函数a中又调用了函数b,所以,这就是一种嵌套调用。
要注意:在函数嵌套调调用过程中程序执行的流程和返
回点的问题。
返回
128
2.7 函数
2.7.4 函数的递归调用
1.函数递归调用的概念
函数的递归调用就是当一个函数在执行的过程中,出
现了直接或间接地调用函数本身的函数调用方式。
下面定义求n!的函数。
long fact(long n)
{ if (n==1)
return 1;
return fact(n-1)*n; //出现了函数fact自己直接调用本
}
身的函数调用
要正确地理解函数的递归调用时,程序执行的流程和返
回点。
返回
129
2.7 函数
2.函数递归调用的条件
递归调用的条件也是我们在定义一个递归函数时应该
遵循的原则。
(1)必须有完成函数任务的语句。如:上例求n!中的
return 1;
(2)有一个确定是否能避免递归调用的测试条件。如果
条件不满足时就递归调用,否则就不再递归调用。
(3)有一个递归调用语句,并且该递归调用语句的参数
应该逐渐逼近不满足条件,以致最后断绝递归。
(4)先测试,后递归调用。在递归函数定义中,必须先
测试,后递归调用。也就是说,递归是有条件的,满足了
条件后,才可以递归。
返回
130
2.7 函数
2.7.5 局部变量和全局变量
从程序中各个变量起作用的范围(作用域)来看,变量可以分为
局部变量和全局变量。
1. 局部变量
在一个函数的内部定义的变量就是内部变量(局部变量)。如:
float f1(int a)
{int b,c;
//a,b,c有效
……
}
void main( )
{int n,m;
//m,n有效
……
}
返回
131
2.7 函数
对局部变量作以下几点说明:
(1)局部变量的作用范围(作用域):只局限在定义它
的本函数体之内。
(2)局部变量的生存期(存在的时间):只有当程序执
行到本函数时,才给这些局部变量分配存储单元,当本
函数执行完毕后,这些局部变量所占存储单元就被释放。
返回
132
2.7 函数
(3)不同函数体中可以定义相同名字的变量,但它们代
表不同的对象,互不干扰。它们在内存占用不同的内存
单元。
(4)函数的形式参数也是该函数的局部变量,其他函数
不能调用。
(5)在一个函数内部,可以在复合语句中定义变量,但
这些变量只在本复合语句中有效,因此,复合语句也可
称为“分程序”或“程序块”。
返回
133
2.7 函数
2.静态局部变量(局部静态变量):
定义方法是:在函数体内定义变量采用:
static 类型标识符 变量名;
特点:
(1)静态局部变量本身也是局部变量,因此其作用域也
是局限在定义它的本函数体内,当离开本函数体,该变量
就不再起作用,但其值还继续保留。
(2)另一方面,静态局部变量又是静态存储类别的变量,
所以,在整个程序运行开始就被分配固定的存储单元(占
用静态存储区),整个程序运行期间不再被重新分配,所
以其生存期是整个程序运行期间。
(3)静态局部变量的赋初值的时间在编译阶段,并不是
每发生一次函数调用就赋一次初值。当再次调用该函数时,
静态局部变量保留上次调用函数时的值。
返回
134
2.7 函数
3.全局变量:
在所有函数体外部定义的变量为外部变量(全局变
量),全局变量可以被本文件中其他函数所调用 (使
用)。
全局变量的有效范围为:从定义该变量的位置开始到
本程序文件的结束。如:
int p=1, q=5;
/*全局变量*/
float f1(int a)
{ int b,c
…… }
char c1,c2;
/* 全局变量 */
返回
135
2.7 函数
char f2(int x, int y)
{ int i,j;
…… }
main()
{int m,n.;
……
}
对全局变量的几点说明:
(1)全局变量在程序的全部执行过程中都占用固定的内
存储单元,而不是仅在需要时才开辟单元,所以其生存期
是整个程序运行期间。
返回
136
2.7 函数
(2)全局变量的作用范围是整个程序文件。全局变量处
于文件的开头定义时,其作用范围为整个文件,否则在定
义点之前的函数内使用时,应在函数体内或外部用extern
说明。 说明的格式是:extern 类型标识符 变量名;
(3)在一个程序文件中定义的全局变量,要在同一程序
的另外一个程序文件中使用时,应在使用它的程序文件中
所有函数体内部或外部对所使用的全局变量用extern说明。
(4)在同一个文件中全局变量与局部变量同名时,则在
局部变量的作用范围内,全局变量不起作用。
4.静态全局变量
当在所有函数体的外部用如下格式定义变量时,则这
种变量称为静态全局变量。
static 类型标识符 变量名;
返回
137
2.7 函数
静态全局变量的特点是:
(1)与全局变量基本相同,只是其作用范围(即作用域)
是定义它的程序文件,而不是整个程序。
(2)静态全局变量属于静态存储类别的变量,所以它在
程序一开始运行时,就被分配固定的存储单元,所以其
生存期是整个程序运行期间。
(3)使用静态全局变量的好处是同一程序的两个不同的
程序文件中可以使用相同名称的变量名,而互不干扰。
2.7.6 全局函数和静态函数
1.全局函数
凡程序中定义的函数,如果未做特别说明,一律都是
全局的。也就是说,函数从本质上是全局的,一个程序
不管有多少个程序文件所组成,在某个程序文件中可以
返回
138
2.7 函数
调用同一程序的另外一个程序文件中定义的函数,只要
对被调函数的原型进行说明即可。声明函数原型的语句:
类型标识符 函数名(形参类型表);
如:假设程序中定义了max函数,则:
int max(int,int);就是对函数max原型的声明。
2.静态函数:
静态函数定义方法为:
static 类型标识符 函数名(形参及其类型)
{ 函数体 }
注意:这种函数就只能在定义它的程序文件中调用。
2.7.7 内联函数
返回
139
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);
}
返回
140
2.7 函数
2.内联函数与普通函数的区别和联系
(1)在定义内联函数时,函数值的类型左面有“inline”
关键字,而普通函数在定义时没有此关键字。
(2)程序中调用内联函数与调用普通函数的方法相同。
(3)当在程序中调用一个内联函数时,是将该函数的代
码直接插入到调用点,然后执行该段代码,所以在调用过
程中不存在程序流程的跳转和返回问题。而普通函数的调
用,程序是从主调函数的调用点转去执行被调函数,待被
调函数执行完毕后,再返回到主调函数的调用点的下一语
句继续执行。
(4)从调用机理看,内联函数可加快程序代码的执行速
度和效率,但这是以增加程序代码为代价来求得速度的。
返回
141
2.7 函数
3.对内联函数的限制
应注意:不是任何一个函数都可定义成内联函数。
(1)内联函数的函数体内不能含有复杂的结构控制语句,
如:switch和while,如果内联函数的函数体内有这些语句,
则编译将该函数视同普通函数那样产生函数调用代码。
(2)递归函数不能被用来作为内联函数。
(3)内联函数一般适合于只有1~5行语句的小函数,对
一个含有很多语句的大函数,没有必要使用内联函数来
实现。
返回
142
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";
返回
143
2.7 函数
whatitis(i);
whatitis(c);
}
在本例中定义了两个名称都叫whatitis的函数,但它们的
形参类型不同。因此,这两个函数就是重载函数。
2.为什么要使用函数重载
在原有C语言中,每个函数必须有其唯一的名称,这样
的缺点是所有具有相同功能、而只是函数参数不一样的
函数,就必须用一个不同的名称,而C++中采用了函数重
载后,对于具有同一功能的函数,如果只是由于函数参
数类型不一样,则可以定义相同名称的函数。
3.匹配重载函数的顺序
由于重载函数具有相同的函数名,在进行函数调用时,
返回
144
2.7 函数
系统一般按照调用函数时的参数个数、类型和顺序来确定被
调用的函数。具体来说,按以下三个步骤的先后次序找到并
调用那个函数:
(1)寻找一个严格的匹配,即:调用与实参的数据类型、
个数完全相同的那个函数。
(2)通过内部转换寻求一个匹配,即:通过(1)的方法没
有找到相匹配的函数时,则由C++系统对实参的数据类型进
行内部转换,转换完毕后,如果有匹配的函数存在,则执行
该函数。
(3)通过用户定义的转换寻求一个匹配,若能查出有唯一
的一组转换,就调用那个函数。即:在函数调用处由程序员
对实参进行强制类型转换,以此作为查找相匹配的函数的依
据。如:
返回
145
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)
返回
146
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)重载函数间不能只是函数的返回值不同,应至少在
形参的个数、参数类型或参数顺序上有所不同。
如:
返回
147
2.7 函数
void myfun(int i)
{………………}
int myfun(int i)
{………………}
这种重载就是错误的。
(2)应使所有的重载函数的功能相同。如果让重载函数
完成不同的功能,会破坏程序的可读性。
返回
148
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
149
返回
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;
}
返回
150
2.7 函数
(2)默认参数的顺序:如果一个函数中有多个默认参数
时,则形参分布中,默认参数应从右至左逐渐定义。如:
void myfunc(int a=1,float b,long c=20);
//错误
void myfunc(int a,float b=2.1,long c=30); //正确
返回
151
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)指针变量名前面的‘*’表示该变量为指针变量,它不是变量
名本身的一部分。
152
(2)此处的类型标识符是该指针变量所要指向的变量的类型。
返回
2.8 指针类型及使用
(3)变量的指针和指向变量的指针变量的区分:指针是
某一变量在内存中所占存储单元的地址 ,是一个地址值。
而指针变量则是专门存放其他变量的地址的变量,是个
变量,如果某一指针变量中存放了另外一个变量的指针,
则称该指针变量是指向那个变量的指针变量。
2.8.1.2 与指针运算有关系的两个运算符
1. &:求某一变量所占存储单元的存储地址。
如:int i=50;
int *ip;
ip=&i; //&i——求变量i 的存储单元的地址(即指针)
此时,指针变量ip存放了变量i的存储地址(指针),因
此称指针变量ip此时是指向变量i的。
返回
153
2.8 指针类型及使用
2. *: 取出指针变量所指向的变量的内容,后面跟指针
变量。
如:*ip为取出指针变量所指向的变量的内容。
即由于ip是指向变量i的,所以*ip 与i是等价的。
2.8.1.3 指针变量的引用
指针变量的引用,即使用指针变量,其使用方法和普
通变量的使用原理一致,但要注意:
(1)指针变量是一个变量:一个指针变量和普通变量一
样,在内存中也占存储单元,因此一个指针变量也相当
于一个容器,所以指针变量也有其指针,这就是指针变
量的指针。
返回
154
2.8 指针类型及使用
(2)指针变量内只能存放其他变量的地址,而不能直
接存放一个普通数据。
(3)一个指针变量只能指向同一个类型的变量,如上
例中指针变量ip只能总是指向整型变量。
(4)一个指针变量只有先指向某一个变量后,才可利
用该指针变量对它所指向的变量进行操作(间接访
问)。
【例2-15】 指针变量及其使用方法。
#include<iostream.h>
void main()
返回
155
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;
}
返回
156
2.8 指针类型及使用
2.8.3 指针与函数
前面讲过,函数的参数可以为整型、实型、字符型等普
通变量。实参与形参间参数的传递是单向的“值传递”。
但函数的参数也可为指针,它的作用是将一个变量的地址
传给被调函数的形参。此时主调函数的调用点上的实参必须
是地址值(指针),而被调函数的形参一定要定义成指针变
量的形式
此时,被调函数的形参得到的是实参的指针,因此,该形
参变量就指向实参,在被调函数中对形参的操作就相当于对
它所指向的实参的操作。
返回
157
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; }
返回
158
2.8 指针类型及使用
2.8.3.1 函数的指针
一个函数在内存中的起始地址就是该函数的指针。
在C++中,函数的名称就代表了该函数的指针。
指向函数的指针变量的一般定义形式为:
数据类型标识符 (*指针变量名)( );
在C++语言中,指针变量可以指向普通变量,它也可以指
向函数。
返回
159
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); }
返回
160
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;
}
返回
161
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—等算数运算是无
意义的。
返回
162
2.8 指针类型及使用
2.8.3.2 把指向函数的指针变量作函数参数
函数的指针变量主要的用途就是把指针作为参数传递
到其它函数。如:
sub(int (*x1)(),int (*x2)())
{ int a,b,i,j;
a=(*x1)(i);
b=(*x2)(j); }
返回
163
2.8 指针类型及使用
2.8.3.3 返回指针值的函数
返回指针值的函数的定义方式为:
类型标识符号 *函数名(参数名)
如:int *a(int x, int y)
{……}
此时,该函数体内的return语句的形式为:return(指针值);
返回
164
【例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; }
165
返回
return(array+*index); }
2.8 指针类型及使用
2.8.4 指针与数组
数组的指针即整个数组在内存中的起始地址;
数组元素的指针是数组中某一元素所占存储单元的地
址。
引用数组元素时是利用数组的下标进行的,也可以利
用指针来进行,
利用指针引用某一数组元素时,即可以先使一指针变
量指向某一数组元素,然后通过该指针变量对它所指向
的数组元素进行操作。
2.8.4.1 指向数组元素的指针变量的定义与赋值
指向数组元素的指针变量的定义与以前定义指针变量
的方法相同,只要注意指针变量定义时的类型要与所要
指向的数组的类型一致即可。
返回
166
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。
返回
167
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]是等价的。
因此,利用此方法就可访问到数组元素。如:
返回
168
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];
}
返回
169
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指向下一个元素),然后再
作*运算。
返回
170
2.8 指针类型及使用
如:若p的初值为a,(即&a[0]),输出*(p++)时,得到a[0]的值,
而输出*(++p),则得到a[1]的值。
(4)(*p)++表示p所指的元素值加1,对上例来说a[0]++。
(5)对于指针的--(自减)运算原理同上。
(6)只有指向数组元素的指针变量才可进行自加或自减
运算。
2.8.4.3 数组名作函数参数
数组名可以用来作为实参和形参。用数组名作实参,
在调用函数时实际上是把数组的首地址传递给形参,这
样,实参数组就与形参数组共占同一段内存,那么形参
数组中元素的值发生变化后,实参数组中各元素的值也
发生变化,但这种变化并不是从形参传回实参的,而是
返回
171
2.8 指针类型及使用
由于形参与实参数共享同一段内存而造成的.
利用数组名作为函数的参数时可以用以下四种情况实现:
(1)形参和实参都用数组名
(2)实参用数组名,形参用指针变量
(3)实参和形参都用指针变量
(4)实参用指针变量,形参用数组名
【例2-19】 函数func是实现数组排序的过程。主函数将8
个整数读入,调用func排序并输出结果。
#include <iostream.h>
void func(int *);
//func的函数原型
void main()
返回
172
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;
}
返回
173
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;
}
}
返回
174
2.8 指针类型及使用
2.8.5 指针与字符串
2.8.5.1 字符串的指针和指向符串的指针变量
字符串在内存中的首地址称字符串的指针
在c++程序中,可以用两种方法来实现字符串的保存:
(1)用字符数组来实现
(2)用字符串指针实现
如: main()
{ char *string=”languaye”;
cout<<string;
}
输出结果:c language
注意:输出时的指针变量的写法是string而不是*string。
返回
175
2.8 指针类型及使用
2.8.5.2 字符串指针作函数参数
可以采用以下4种方法:
实参
形参
(1)数组名
数组名
(2)数组名
字符指针变量
(3)字符指针变量
字符指针变量
(4)字符指针变量
数组名
【例2-20】 将字符串a复制为字符串b。
返回
176
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; }
返回
177
2.8 指针类型及使用
2.8.6 指针数组和指向指针的指针.
1. 指针数组
如果一个数组中的元素均为指针类型的数据,则称这
个数组为指针数组。其定义方式为:
类型标识符 * 数组名[数组长度]
如:int *p[4] ;
这种指针数组比较适合于处理字符串。如:
char *name[3]={“fortranm”,”basic” ,”pascal”};
2. 指向指针的指针.
前面已经介绍过指针数组.
返回
178
2.8 指针类型及使用
如: char *name[3]
说明该数组中的元素都是指针,数组代表了该指针
数组的起始地址,name是指向指针型数据的指针。
定义指向指针的指针变量的方式为:
类型标识符号 **变量名
如:char **p;
**p相当于*(*p),说明指针变量p是指向一个字符指
针变量(指向字符型数据的指针变量)的。
返回
179
2.9 引用
2.9.1 引用的概念、声明和使用
1.引用及声明方法
引用就是某一变量(目标)的一个别名,这样对引用
的操作就是对目标的操作。
引用的声明方法:
类型标识符 &引用名=目标变量名;
如:int a;
int &ra=a; //定义引用ra,它是变量a的引用,即别名
说明:
(1)&在此不是求地址运算,而是起标识作用。
(2)类型标识符是指目标变量的类型。
(3)声明引用时,必须同时对其进行初始化。
返回
180
2.9 引用
(4)引用声明完毕后,相当于目标变量名有两个名称,
即该目标原名称和引用名。
(5)声明一个引用,不是新定义了一个变量,它只表示
该引用名是目标变量名的一个别名,所以系统并不给引
用分配存储单元。
2.引用的使用
(1)一旦一个引用被声明,则该引用名就只能作为目标
变量名的一个别名来使用,所以不能再把该引用名作为
其他变量名的别名,任何对该引用的赋值就是该引用对
应的目标变量名的赋值。
(2)对引用求地址,就是对目标变量求地址。
返回
181
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;
返回
182
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)由于指针变量也是变量,所以,可以声明一个指针
变量的引用。方法是:
类型标识符 *&引用名=指针变量名;
返回
183
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;
}
返回
184
2.9 引用
(4)不能建立数组的引用,因为数组是一个由若干个元
素所组成的集合,所以就无法建立一个数组的别名。
(5)引用是对某一变量或目标对象的引用,它本身不是
一种数据类型,因此引用本身不占存储单元,这样,就
不能声明引用的引用,也不能定义引用的指针。
如: 下例中的操作是达不到的。
int a;
int &ra=a;
int &*p=&ra; //错误
(6)不能建立空指针的引用,如:不能建立
int &rp=NULL;
返回
185
2.9 引用
(7)也不能建立空类型void的引用,如:不能建立
void &ra=3;因为尽管在C++语言中有void数据类型,但
没有任何一个变量或常量属于void类型。
2.9.2 用引用作为函数的参数
1.引用作为函数的参数
一个函数的参数也可定义成引用的形式,如:我们定
义交换两个数的函数swap,将函数的参数定义成引用
的形式:
返回
186
2.9 引用
void swap(int &p1, int &p2) //此处函数的形参p1, p2都是引用
{ int p;
p=p1;
p1=p2;
p2=p;
}
为在程序中调用该函数,则相应的主调函数的调用点处,
直接以变量作为实参进行调用即可,而不需要实参变量有
任何的特殊要求。如:对应上面定义的swap函数,相应的
主调函数可写为:
返回
187
2.9 引用
main()
{ int a,b;
cin>>a>>b; //输入a,b两变量的值
swap(a,b); //直接以变量a和b作为实参调用swap函数
cout<<a<<‘ ’<<b; //输出结果 }
上述程序运行时,如果输入数据10 20并回车后,则输
出结果为20 10。
返回
188
2.9 引用
2.几点说明
由上例可看出:
(1)传递引用给函数与传递指针的效果是一样的,这时,
被调函数的形参就成为原来主调函数中的实参变量或对
象的一个别名来使用,所以在被调函数中对形参变量的
操作就是对其相应的目标对象(在主调函数中)的操作。
(2)使用引用传递函数的参数,在内存中并没有产生实
参的副本,它是直接对实参操作;而使用一般变量传递
函数的参数,当发生函数调用时,需要给形参分配存储
单元,这样形参与形参就占用不同的存储单元,所以形
参变量的值是实参变量的副本。因此,当参数传递的数
据量较大时,用引用比用一般变量传递参数的效率和所
占空间都好。
返回
189
2.9 引用
(3)使用指针作为函数的参数虽然也能达到与使用
引用的效果,但是,在被调函数中需要重复使用“*
指针变量名”的形式进行运算,这很容易产生错误且
程序的阅读性较差;另一方面,在主调函数的调用点
处,必须用变量的地址作为实参。
返回
190
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;
}
返回
191
2.9 引用
2.9.3 如何使一个被调函数同时返回多个值
由于函数的返回值是通过函数体中的return语句完成的,
但一个return语句只能返回一个值,为此,我们可以采用
以下方法:
(1)利用全局变量的方法:可以在程序的开头定义一些
全局变量。这样,当被调函数执行完毕后,所需要的数
据已保存在了全局变量中,在主调函数中直接读取全局
变量的值即可。
(2)使用指针或数组的方法:因为在指针作为函数的情
况下,可将主调函数的某些变量的地址传递给被调函数。
返回
192
2.9 引用
(3)利用引用的方法:通过前面的学习,我们知道,使
用引用传递参数,可以在被调函数中改变主调函数中目标
变量的值,这种方法实际上就是可以使被调函数返回多个
值。
【例2-22】 使用引用使函数返回多个值。以下定义了可以
同时返回10个数中的最大值和最小值的函数max_min。
返回
193
2.9 引用
#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;
}
返回
194
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赋值
}
}
返回
195
2.9 引用
2.9.5 一个返回引用的函数值作为赋值表达式的左值
一般情况下,赋值表达式的左边只能是变量名,即被
赋值的对象必须是变量,只有变量才能被赋值,常量或
表达式不能被赋值,但如果一个函数的返回值是引用时,
赋值号的左边可以是该函数的调用。
【例2-24】 测试用返回引用的函数值作为赋值表达式的
左值。
#include <iostream.h>
int &put(int n);
int vals[10];
int error=-1;
void main()
返回
196
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; }
}
返回
197
2.9 引用
2.9.7 引用总结
(1)在引用的使用中,单纯给某个变量取个别名是毫无
意义的,引用的目的主要用于在函数参数传递中,解决大
对象的传递效率和空间不如意的问题。
(2)用引用传递函数的参数,能保证参数传递中不产生
副本,提高传递的效率,且通过const的使用,保证了引用
传递的安全性。
(3)引用与指针的区别是,指针通过某个指针变量指向
一个对象后,对它所指向的变量间接操作,程序中使用指
针,程序的可读性差;而引用本身就是目标变量的别名,
对引用的操作就是对目标变量的操作。
返回
198
2.10 结构体、共用体和枚举
2.10.1 结构体
数组中的各元素是属于同一类型的,但有时需要将不
同类型的数据组合成一个有机的整体,并且这些数据是
相互联系的,这就引出了结构体。结构体是由多种类型
的数据组成的整体。组成结构体的各个分量称为结构体
的数据成员(简称成员)。
2.10.1.1 定义结构体
定义结构体的一般格式为:
struct 结构体名
{
成员列表
}变量名列表;
返回
199
2.10 结构体、共用体和枚举
结构体定义是以关键字struct开始的,结构体名应是有
效的C++标识符。结构体中的每个成员都必须通过定义来
确定成员名及其类型。例如:
struct student
{ int num;
//学号
char name[20];
//姓名
char sex;
//性别
int age;
//年龄
}student1;
其中,student是定义的结构体名,该结构体有四个成员变
量num、name、sex、age。student1是定义的结构体变量。
返回
200
2.10 结构体、共用体和枚举
也可以在结构体定义后再定义结构体变量。格式是:
struct 结构体名 变量名列表;
如:
struct student
{
int num;
//学号
char name[20];
//姓名
char sex;
//性别
int age;
//年龄
};
struct student student1;
student student1;
返回
201
2.10 结构体、共用体和枚举
2.10.1.2 结构体变量的初始化
可采用以下两种方法:
(1)在定义结构体类型的同时,为结构体变量初始化。
struct 结构体名
{ 成员列表
}变量名={初始值列表};
如:struct student
{int num;
//学号
char name[20];
//姓名
char sex;
//性别
int age;
//年龄
}student1={9901, "wang",‘f’,23};
返回
202
2.10 结构体、共用体和枚举
(2)利用已有的结构体类型定义结构体变量,并同时初
始化。格式是:
结构体名称 变量名={值1,值2,……};
如:student stu={1,”zhang”,’M’,20,90.0};
2.10.1.3 结构体变量的引用
定义了结构体变量以后,就可以在程序中使用这些变
量。引用结构体变量时应注意:
(1)不能将结构体变量作为一个整体来引用,只能引用
结构体变量中的成员。
结构体变量名.成员名
返回
203
2.10 结构体、共用体和枚举
如:cout<<student1.name;
此处的“.”是成员运算符,它的优先级别最高。
(2)多级引用。
(3)对结构体成员变量的使用可像普通那样进行,如:
进行赋值,参加运算等。如:
struct student s1,s2;
s1.num=9901;
s2.num=s1.num+1;
返回
204
2.10 结构体、共用体和枚举
(4)可以将一个已有值的结构体变量的值直接赋给另外
一个相同类型的结构体变量。方法是:
结构体变量名1=结构体变量名2;
如:student st1={1,”zhang”,’M’,20,90.0};
student st2; st2=st1;
(5)可以应用成员的地址。也可以引用结构体变量的地
址。如:
&student.num &st1
返回
205
2.10 结构体、共用体和枚举
2.10.1.4 结构数组
结构数组:即数据类型为结构体类型的数组,这样,
数组中的每个元素都属于同一种结构体类型,每一元素都
分别包含了结构体中的每个成员。
1. 结构数组的定义
Struct student
{int num;
char name[20];
int age;
float score;
char addr[30];};
student stu[3];
返回
206
2.10 结构体、共用体和枚举
2.结构体数组的初始化
结构体数组在定义时也可以进行初始化。其初始化方
法与一般数组的初始化方法基本相同,只是必须为每个
元素提供各结构成员的值,如:
struct student
{ int num;
char name[20];
char sex;
返回
207
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】指向结构体变量的指针的使用。
返回
208
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成员赋值
返回
209
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;
}
返回
210
2.10 结构体、共用体和枚举
程序的运行结果:
1
li lin M
89
1
li lin M
89
1
li lin M
89
可见,三种访问结构体变量各成员的值的结果完全相同。
程序说明:
(1)上例中(*p).num也可写为p->num。
(2)结构体取成员的运算可以采用以下三种形式:
① 结构体变量名.成员名
②(*结构体指针变量名).成员名
③ 结构体指针变量名->成员名
2.指向结构体数组的指针
返回
211
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()
返回
212
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指向数组的下一个元素,利用这种方法可
以访问数组中所有元素的值。
返回
213
2.10 结构体、共用体和枚举
2.10.1.6 用结构体类型作为函数的参数
1.用结构体类型的变量作函数的参数(传值)
注意:此时主调函数的调用点上的实参与被调函数相应
位置上的形参必须是相同的结构体类型。
【例2-28】用结构体类型的变量作为函数的参数。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
返回
214
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;}
返回
215
2.10 结构体、共用体和枚举
程序的执行结果是:
1
li lin M
18
2
sum M
19
3
zhao M
20
可见,当把一个结构体类型的变量作为函数的参数时,
可以将该变量的值(包含结构体类型中各成员的值)传
递给被调函数的形参。
2.用指向结构体的指针作函数的参数(传指针)
用指向结构体变量的指针作参数。这种方式同指针作
为函数的参数的原理一致,传递的是结构体变量的地
址(指针)。
返回
216
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}};
返回
217
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.用结构体变量的引用作为函数的参数
此时,被调函数的形参必须声明成引用形式,函数的
形参作为实参的一个别名来使用,从而达到对实参操作
的目的。
返回
218
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}};
返回
219
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.返回结构类型值的函数的定义
其定义格式如下:
返回
220
2.10 结构体、共用体和枚举
结构体名称 函数名(形参及类型说明)
{ 函数体 }
【例2-31】定义一个返回结构体类型的函数,求所有同学
中年龄最大的同学。
#include "iostream.h"
struct student
{ int num;
char name [20];
char sex;
int age ;
};
student max(student *,int);
返回
221
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));
}
返回
222
2.10 结构体、共用体和枚举
2.返回结构的引用的函数
略!
2.10.1.8 结构的嵌套
在以下的结构定义中,其中birth成员是birthday结构体
类型。
struct birthday{int year;int month;int day;};
struct student
{int num;
char sex;
返回
223
2.10 结构体、共用体和枚举
birthday birth; };
student stu; //定义student结构体类型的变量stu
此时要访问stu的birth成员的值时,要注意使用多个“.”
操作符。如:stu.birth.year=1980;
返回
224
2.10 结构体、共用体和枚举
2.10.2 堆内存的分配和释放
2.10.2.1 申请分配内存的方式
从内存中申请分配内存的方法有以下两种:
(1)利用malloc函数
格式是:void * malloc(字节数)
该函数如分配内存成功,则返回其起始地址,否则返
回NULL。当程序中使用malloc函数动态分配内存时,应
该在程序的头部嵌入相应的头文件:#include <stdlib.h>
返回
225
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
返回
226
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分配内存时则不需要类型转换。
返回
227
2.10 结构体、共用体和枚举
2.10.2.2 释放内存的方式
(1)利用free函数。
格式:free(起始内存地址);
(2)利用delete运算符:
格式1:delete 指针变量名;
格式2:delete [ ] 指针变量名;
说明:格式1可释放某一个内存单元;而格式2可释放
若干个内存单元的空间。如:
#include <iostream.h>
#include <stdlib.h>
返回
228
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所指向的所有内存空间
}
返回
229
2.10 结构体、共用体和枚举
2.10.3 共用体类型
1.共用体概念
几个不同的变量共一段内存的结构称为共用体类型的结
构也叫联合。
2. 共用体类型的定义
其定义格式为:
union 共用体名
{成员表} 变量表;
返回
230
2.10 结构体、共用体和枚举
如: union data {int i;
char ch;
float f;
}a,b,c;
这表示定义了共用体类型data,并同时定义了属于该种数
据类型的变量a,b,c。
由此可见:其定义方式与结构的定义方式类似,但二
者的含义不同,结构体变量所占内存空间的大小,是各
成员所占的内存之和,每个成员分别占有自己的内存单
元,而共用体变量所占的内存空间大小于等于占用内存
空间最大的成员的长度,如上面定义的a,b,c三个共用体变
量分别占4个字节。
返回
231
2.10 结构体、共用体和枚举
3.共用体变量的定义
同结构体变量的引用.
4.共用体变量的引用
共用体变量的使用方法基本同结构体变量的使用方法,
并同时注意以下原则:
(1)不能直接使用共用体变量,而只能使用共用体变量
的成员,共用体变量取成员的运算符同结构体变量取成
员的运算符,即用“.”。
返回
232
2.10 结构体、共用体和枚举
如:对于上例定义的共用体变量a来说,可用以下方法引
用其中的成员:
a.i 引用共用体变量a中的整型变量i
a.ch 引用共用体变量a中的整型变量ch
a.f 引用共用体变量a中的整型边量f
(2)共用体类型的特点:共用体类型可以使用覆盖技术
使几个不同类型的变量(成员)共同占用和使用一块内
存空间,所以,在每一瞬时只有一个成员起作用,其他
的成员不起作用。
(3)共用体变量中当前正在起作用的成员是最后一次存
放的成员,在存入一个新的成员后原有的成员就失去作
用,如:
返回
233
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 枚举类型名{枚举元素表}枚举变量名;
返回
234
2.10 结构体、共用体和枚举
如:enum weekday{sun,mon,tue, wed,thu,fri,sat} workday;
2.枚举变量的定义
同结构体变量定义.
如 : 可 以 利 用 已 有 的 枚 举 类 型 weekday 定 义 变 量 enum
weekday myworkday;
返回
235
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。
返回
236
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;
返回
237
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;
注意:
类型定义名一般用大写。
返回
238
2.10 结构体、共用体和枚举
2.10.6 编译预处理
在C++程序的源代码中可以使用各种编译指令,这些指
令称为编译预处理命令。C++提供的预处理命令主要有以
下三种:
• 宏定义命令
• 文件包含命令
• 条件编译命令
这些命令在程序中都是以“#”来引导,每条预处理命
令必须单独占用一行;它们不是C++的语句,因此在结尾
没有分号“;”。
1. 宏定义命令
返回
239
2.10 结构体、共用体和枚举
宏定义的一般形式为:
#define 宏名 字符串
其中:define是宏替换的关键字,“宏名”是需要替换
的标识符,“字符串”是被指定用来替换的字符序列。
如:#define PI 3.1415926
说明:
(1)#define、宏名和字符串之间一定要有空格。
(2)宏名一般用大写字母表示,以区别于普通标识符。
(3)宏被定义以后,一般不能再重新定义。但可以用
#undef来终止宏定义。
(4)一个定义过的宏名可以用来定义其他新的宏,但要
注意其中的括号。如:
返回
240
2.10 结构体、共用体和枚举
#define A 20
#define B (A+10)
(5)还可以有带参数的宏替换。如:
#define MAX(a,b) ((a)>(b)?(a):(b))
2. 文件包含命令
所谓“文件包含”是指将另一个源文件的内容合并到
当前程序中。C++中,文件包含命令的一般形式为:
#include<文件名> 或 #include”文件名”
文件名一般是以.h为扩展名,因而称它为“头文件”,
文件包含的两种格式区别在于:将文件名用“< >”括起
来,用来包含那些由系统提供的并放在指定子目录中头
返回
241
2.10 结构体、共用体和枚举
文件;将文件名用双引号括起来的,用来包含用户自己
定义的放在当前目录或其他目录下的头文件或其他源文
件。
文件包含可以将头文件中的内容直接引入,而不必再
重复定义,减少了重复劳动,节省了编程时间。
注意:一条#include命令只能包含一个文件,若想包含
多个文件,则应使用多条包含命令。
3. 条件编译命令
在一般情况下,源程序中的所有语句都会参加编译,
但是有时候会希望根据一定的条件编译源文件的部分语
句,这就是“条件编译”。条件编译使得同一源程序在
不同的编译条件下得到不同的目标代码。
在C++中,常用的条件编译命令有如下三种:
返回
242
2.10 结构体、共用体和枚举
(1)#ifdef 标识符
程序段1
#else
程序段2
#endif
该条件编译命令的功能是:如果在程序中定义了指定
的“标识符”时,就用程序段1参与编译,否则,用程序
段2参与编译。
(2)#ifndef 标识符
程序段1
#else
程序段2
#endif
返回
243
2.10 结构体、共用体和枚举
该条件编译命令的功能是:如果在程序中未定义指定
的“标识符”时,就用程序段1参与编译,否则,用程序
段2参与编译。
(3)#if 常量表达式1
程序段1
#elif常量表达式2
程序段2
……
#elif常量表达式n
程序段n
#else
程序段n+1
#endif
返回
244
2.10 结构体、共用体和枚举
该条件编译命令的功能是:依次计算常量表达式的值,
当表达式的值为真时,则用相应的程序段参与编译,如
果全部表达式的值都为假,则用else后的程序段参与编译。
2.10.7 文件及其操作
文件是指存储在存储介质上的数据的集合。C++将文件
看作是由一个一个字符(字节)的数据顺序组成的。它
的组成形式可以分为:ASCII文件和二进制文件。ASCII
文件又称文本文件,它的每一个字节存放一个ASCII代码,
代表一个字符;二进制文件是将数据用二进制形式存放
在文件中,它保持了数据在内存中存放的原有格式。
无论是文本文件还是二进制文件,都需要用“文件指针”
来操纵。一个文件指针总是和一个文件相关联,当文件
每一次打开时,文件指针指向文件的开始,随着对文件
的操作,文件指针不断地在文件中移动,并一直指向最
返回
245
2.10 结构体、共用体和枚举
后处理的字符(字节)位置。
对文件的操作有两种方式:顺序文件操作和随机文件
操作。
2.10.7.1 顺序文件操作
顺序文件操作,即从文件的第一个字符(字节)开始,
顺序地处理到文件的最后一个字符(字节),文件指针
相应地从文件的开始位置到文件的结尾。
顺序文件操作包括打开文件、读写文件和关闭文件三
个步骤。
文件的打开和关闭是通过使用fstream类的成员函数open
和close来实现的。fstream类是用来对文件流进行操作,
它和前面的标准输出输入流(cout、cin)一起,是C++实
现流操作的最基本的类,而且它们有一个共同的基类ios。
为了能使用这些类的相关函数,还必须在程序中添上相
返回
246
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类中定义的文件打开方式
返回
247
2.10 结构体、共用体和枚举
表2.13 在ios类中定义的文件打开方式
文件打开方式
含 义
in
以输入(读)方式打开文件
out
以输出(写)方式打开文件
app
打开一个文件使新的内容始终添加在文件的末尾
ate
文件打开时,文件指针位于文件尾
trunc
若文件存在,则清除文件所有内容;否则,创建新文件
binary
以二进制方式打开文件,缺省时以文本方式打开文件
nocreat
打开一个已有文件,若该文件不存在,则打开失败
noreplace
若打开的文件已经存在,则打开失败
ios::in|ios::out
以读/写方式打开文件
ios::in|ios::binary
以二进制读方式打开文件
ios::out|ios::binary
以二进制写方式打开文件
返回
248
2.10 结构体、共用体和枚举
2. 关闭文件
在文件操作结束时,应及时调用成员函数close()来关
闭文件。如要关闭的文件名为myfile,则可使用如下语句
关闭文件:
myfile.close();
3. 文件的读写
在打开文件后,就可以对文件进行读写操作了。
【例2-32】 向文本文件中分别写入一个整数、一个浮点
数和一个字符串,并读出其中的信息。
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
返回
249
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();
}
返回
250
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为文件指针的参照位置,其可能值为:
返回
251
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个操作读指针的成员函
数相同,只不过它们是用来操作写指针的。
返回
252
本章小结
本章是C++语言的基础,内容与C语言多数一致。
C++语言支持面向对象的程序设计(OOP),在面向
对象的程序设计中,以“对象”为中心,并且将对象的
属性和方法二者封装在一起,这种结合自然地反映了应
用领域的模块性,因此具有相对稳定性。同时OOP又引
入了“类”(class)的概念。类与类以层次结构组织,
属于某个类的对象除具有该类所描述的特性外,还继承
了层次结构中该类上层所有类描述的全部性质,OOP方
法的模块性与继承性,保证了新的应用程序设计可在原
有对象的数据类型和功能的基础上,通过重用、扩展和
细化来进行,而不必从头做起或复制原有代码,这样,
大大减少了重新编写新代码的工作量,同时降低了程序
设计过程中出错的可能性,达到了事半功倍的效果。
返回
253
本章小结
一个C++的程序是由函数构成的,程序中有且仅有一
个main函数,它总是从主函数main开始运行。每个C++的
源程序要以.CPP作为程序存盘时的文件名后缀,源程序
需要经过C++编译系统的编译和连接,最后才能产生可运
行的.EXE程序文件。C++源程序数据的输入和输出通常
利用输入/输出流对象cin和cout来完成,这时要求在程序
的开头需要嵌入头文件iostream.h。
程序的核心任务是对数据进行加工和处理,在C++中
任何数据是有类型的,不同的数据类型的关键字不同,
所占存储单元的大小不同,因而表示数的范围大小也不
同。另外,根据数据在程序运行过程中是否发生变化将
数据分为常量和变量,常量的值固定不变且数据类型是
由用户在程序中的书写格式来决定,而变量则必须在程
返回
254
本章小结
中进行明确的定义,即定义其名称和类型,在程序中,
任何变量都要遵循先定义后使用的规则。
C++为每种运算符规定了一个运算的优先级和结合特
性,以控制各种运算的顺序,利用圆括号可以改变表达
式的运算顺序。当在表达式中进行运算的数据类型不同
时,C++将自动进行隐式转换,当然,用户也可利用强制
类型转换的方法进行转换。
利用程序的三种结构即:顺序结构、选择结构和循环
结构可以实现对程序执行流程的控制。选择结构可使程
序根据某个(些)条件是否成立,从而有选择的执行程
序中的程序段,这可以利用if语句实现。而循环结构可使
某一段程序有条件地重复执行有限次,可利用while、dowhile和for语句实现,并且这些语句可以通过改变条件的
形式进行相互转化。
返回
255
本章小结
数组是一个由若干相同类型的变量组成的集合,数组
中特定的元素通过下标来访问,同一个数组中所有元素
所占存储单元是连续的,整个数组所占存储单元的首地
址就是数组中的第一个元素的地址,数组名本身代表了
数组的首地址。当数组用于存放字符串时,由于字符串
具有结束标记‘\0’,所以在定义字符数组的大小时,要
多定义一个元素。
指针就是某一存储单元的地址,指针变量是专门存放
其他变量指针的变量,当指针变量中存放了某一变量的
地址时,则称该变量指向那个变量。因此,指针变量可
以指向变量、数组、函数、字符串、结构体等。指针还
可以作为函数的参数,以传递实参的地址。
当程序代码量较大时,可根据功能的不同分成更小、
更容易管理的模块,这种模块就是函数。程序中所用的
返回
256
本章小结
函数有两类,一类是库函数,另一类是用户自定义函数,
库函数可直接使用,而用户自定义函数要先定义后使用。
一个函数可定义成有参函数,也可定义成无参函数,当函
数无返回值时,要把函数的类型定义成void。定义函数时,
函数名称后面括号内的参数是形式参数,形式参数可以是
普通变量、数组名、指针变量、引用等。当发生函数调用
时,实参与形参间发生了数据传递,要注意传值与传地址
间的区别。
内联函数是为了提高编程的效率而实现的,它适用于
函数体代码较少且程序中不含有复杂程序结构的情况。函
数重载允许用同一个函数名定义多个函数,系统会根据传
递给函数的参数的数目、类型和顺序调用相匹配的函数,
函数重载使程序设计简单化。
在函数定义中通过赋值运算可指定参数的默认值。
返回
257
本章小结
引用是C++语言独有的特性,引用就是某一变量的别
名,在定义时必须初始化,使用引用的主要目的是在函数
参数传递过程中解决大对象的传递效率和空间不如意的问
题。当利用引用作为函数的参数时,参数的传递过程中不
产生值的副本。不允许声明引用数组,但可以用常量来初
始化引用声明。当一个函数返回引用时,要注意局部对象
返回的危险。
结构体是一种将不同数据类型的成员组织到一起的构
造数据类型,因此,当定义结构体时,不产生内存的分配,
只有在定义了结构体的变量时,才分配内存单元。当结构
体作为函数的参数进行传递时,其值进行了复制,因此,
当结构体很大时,宜采用结构体的引用传递函数参数。在
使用结构体变量时,不能直接把它当成一个整体去使用,
返回
258
本章小结
而只能访问和使用结构体中的成员。结构体取成员的方
法是“结构体变量名.成员名”。另外,在程序中可以定
义结构体数组,也可以定义指向结构体的指针。
利用new运算符可以进行动态地分配内存,利用delete
运算符可以释放已分配的内存。
C++允许使用关键字typedef为已有的数据类型定义新
的名称,称为类型定义。类型定义只是为已有的数据类
型生成一个别名,并不是定义了新的数据类型。
数据文件的打开和关闭是通过使用fstream类的成员函
数open和close来实现的。fstream类是用来对文件流进行
操作,它和标准输出输入流(cout、cin)一起,是C++实
现流操作的最基本的类,而且它们有一个共同的基 类ios。
为了能使用这些类的相关函数,还必须在程序中添上相
关的包含文件iostream.h和 fstream.h。
返回
259