第2章 数据类型、运算符和表达式
第2章 数据类型、运算符和表达式
C++语言的数据类型
C++程序中的每个变量或常量都要拥有一种数据类型。C++中的数据类型大体可以分成三类:基本类型、导出类型和用户定义类型。
基本类型是由C++语言预先定义好的数据类型,包括:逻辑型、字符型、整型、浮点型和空值型。导出类型是由某种已知类型构造出来的数据类型,包括:数组、指针和引用。用户定义类型是指必须由用户给出具体定义后才能使用的数据类型,包括:枚举类型和类类型。
本章仅介绍基本类型和用户定义类型中的枚举类型。导出类型和类类型将分别在第\(4\)章和第\(6\)章中进行介绍。
基本类型
1.逻辑型
逻辑型用关键字bool
表示,因此又称为bool
型(布尔型)。逻辑型的取值只包含true
和false
,它们都是C++关键字。其中,true
对应整数\(1\),表示逻辑真;false
对应整数\(0\),表示逻辑假。
2.字符型
字符型用关键字char
表示,因此又称为char
型。字符型的取值范围是全部基本字符以及ASCII 码集或扩充 ASCII 码集对应的全部符号。字符型数据占用\(1\)字节(Byte),,即\(8\)位(bit)空间。C++语言提供的字符型与整型关系密切,字符集与单字节整数存在对应关系(ASCII码),例如,字母a的ASCII码值是\(97\),因此还可以将字符型看作是用来表示单字节整数的整型,字符型在整数中的取值范围是\(-128 \sim 127\)(有符号字符型)或\(0 \sim 255\)(无符号字符型)。
3.整型
整型用关键字int
表示,因此又称为int
型,它是C++中最常用的数据类型,程序设计中经常使用的整数如\(0、123、-456\)等都是整型数据。由于计算机的存储空间有限,因此整型数据的取值范围是计算机所能表示的全部整数。例如,一般的有符号短整型数的取值范围是\(-32 768 \sim 32 767\)。整型数据所占据的存储空间大小根据机器的不同而有所差别。例如,在\(16\)位计算机中,整型变量占\(2\)个字节,而在\(32\)位计算机中,整型变量占\(4\)个字节。
4.浮点型
浮点型包括单精度型和双精度型两种,单精度型用关键字float
表示,又称float
型;双精度型用关键字double
表示,又称double
型。它们对应着数学中实数的概念,即带有小数点的数。
C++中的浮点数可以采用尾数加阶码的表示形式,其中单精度型的取值范围是\(-3.4E38 \sim 3.4E38\),但不能超过\(7\)位有效数字,如果有效数字超出\(7\)位,则舍去第\(7\)位以后的数字;双精度型的取值范围是\(-1.7977E308 \sim 1.7977E308\),但不能超过\(15\)位有效数字,如果有效数字位数超出\(15\)位,则舍去第\(15\)位以后的数字。
float
型数据一般占用\(4\)字节(Byte),即\(32\)位(bit)空间;double
型数据一般占用\(8\)字节(Byte),即\(64\)位(bit)空间。
5.空值型
空值型用关键字void
表示,因此又称为void
型。空值型的取值为空。C++中不存在void
型的露量或变量。C++语言规定,所有函数说明都必须指明返回值类型,没有返回值的函数应说明为void
类型;另外,void
类型还可以用来声明一个指针变量,例如:
void *p
是一条指针变量声明语句,其中指针变量p
所指向的数据类型尚不确定。
基本类型的派生类型
C++语言中,基本类型的字长及其取值范围可以放大和缩小,改变后的类型就叫作基本类型的派生类型。派生类型声明符由基本类型关键字char
、int
、 float
、double
前面加上类型修饰符组成。类型修饰符包括:
short | 短类型,缩短字长 |
---|---|
long | 长类型,加长字长 |
signed | 有符号类型,取值范围包括正负值 |
unsigned | 无符号类型,取值范围只包括正值 |
表2.1列出了基本类型及其常用派生类型在\(32\)位计算机上占用的字节长度和取值范围。
表2.1 C++基本数据类型及其派生类型的描述
类型 | 声明符 | 长度(字节) | 取值范围 |
---|---|---|---|
有符号短整数 | short 或short int 或signed short int |
\(2\) | \(-2^{15} \sim 2^{15}-1\)内的整数 |
无符号短整数 | unsigned short 或unsigned short int |
\(2\) | \(0 \sim 2^{16}-1\)内的整数 |
有符号整数 | int 或signed int |
\(4\) | \(-2^{31} \sim 2^{31}-1\)内的整数 |
无符号整数 | unsigned 或unsigned int |
\(4\) | \(0 \sim 2^{32}-1\)内的整数 |
有符号长整数 | long 或long int 或signed long int |
\(4\) | \(-2^{31} \sim 2^{31}-1\)内的整数 |
无符号长整数 | unsigned long 或unsigned long int |
\(4\) | \(0 \sim 2^{31}-1\)内的整数 |
有符号字符 | char 或signed char |
\(1\) | \(-128 \sim127\)内的整数 |
无符号字符 | unsigned char |
\(1\) | \(0 \sim 255\)内的整数 |
单精度数 | float |
\(4\) | \(-3.402 823×10^{38} \sim 3.402 823×10^{38}\)内的数 |
双精度数 | double |
\(8\) | \(-1.797 7×10^{308} \sim 1. 797 7 \times 10^{308}\)内的数 |
长双精度 | long double |
\(8\) | \(-1.797 7×10^{308} \sim 1. 797 7 \times 10^{308}\)内的数 |
空值 | void |
实际上还可以使用派生类型名的简化形式,其效果与完整的派生类型名等价。例如,可以用long
来代替long int
,用unsigned long
来代替unsioned long int
。表2.1“声明符”一栏中给出的等价类型名之间用“或”字分隔。
常量
常量是指在程序执行过程中值不改变的量。常量有两种表示形式,即字面常量和符号常量。字面常量的类型是根据书写形式来区分的,例如\(15\),\(-2\),\(26\),'a ',"hello world"等都是字面常量,它们的类型分别为:整型、浮点型、字符型、字符串型,每个字面常量的字面本身就是它的值。符号常量是一个标识符,在程序中必须遵循“先声明,后使用”的原则。关于符号常量的定义和使用方法将在 变量 中介绍。
逻辑常量
前面介绍过的逻辑类型只包含两个取值:true
和false
,它们称为逻辑常量。例如,对于两个整型数x
和y
:
bool b=(x==y);
如果x
与y
相等,则b
的值为true
;否则b
的值为false
。
逻辑常量主要用在逻辑运算中。此外,由于逻辑值对应着整数\(1\)或\(0\),所以它也能够像其他整数一样出现在表达式中,参与各种整数运算。
字符常量
字符常量简称字符,它以单引号作为起止符号,中间有一个或若十个字符。例如,'a'
和'&'
,单引号中间有一个字符,这是一般意义上的字符常量;除此之外还有一种特殊形式的字符常量,例如'\n '
,'\146'
,'\x6E'
等以\
开头的包括多个字符的字符序列也都是符合规定的字符常量。但是,无论字符常量包含一个还是多个字符,每个字符常量只能表示一个字符,当字符常量的一对单引号内多于一个字符时,则将按照一定的规则解释为一个字符。例如,'a'
表示字符a,'\146'
实际上表示字符f。
计算机中常用的 ASCII 字符也是字符型的数据,因为 ASCII码值在\(0\sim127\)之间,正好落在字符型数据的取值范围之内。 ASCII 字符集中的每一个可显示字符(个别字符除外)都可以作为一个字符常量。但是,对于一些特殊的字符,如回车、换行等具有控制功能的字符,或者像单引号、双引号等作为特殊标记使用的字符,就无法直接采用单引号作为起止符号来表示。为了表示这些特殊字符,C++中引入了“转义”字符的概念,其含义是:用反斜线\
引导的下一个字符失去了原来的含义,而转义为具有某种控制功能的字符。例如,'\n'
中的字符n通过反斜线的转义后就成为一个换行符,其 ASCII 码为\(10\)。为了表示作为特殊标记使用的可显示字符,也需要用反斜线字符引导,例如,\'
表示单引号字符,若直接使用'
表示单引号是不行的。另外,还允许用反斜线引导一个具有\(1\)至\(3\)位的八进制整数或一个以字母\(x\)(大、小写均可)作为开始标记的具有\(1\)至\(2\)位的十六进制整数,对应的字符就是以这个整数作为 ASCII 码的字符。例如,\0
\12
\73
\x5A
对应的字符依次为空字符,换行符,
;
和Z
。
由反斜线字符引导的符合上面规定的字符序列称为转义序列。表2.2列出了C++中的字符转义序列。
转义序列 | 对应值 | 功能 |
---|---|---|
\a |
\(7\) | 响铃 |
\b |
\(8\) | 退格 |
\f |
\(12\) | 换页 |
\n |
\(10\) | 换行 |
\r |
\(13\) | 回车 |
\t |
\(9\) | 水平制表 |
\v |
\(11\) | 垂直制表 |
\\ |
\(92\) | 反斜线 |
\' |
\(39\) | 单引号 |
\" |
\(34\) | 双引号 |
\? |
\(63\) | 问号 |
\ooo |
ooo 的十进制值 |
表示\(1\sim3\)位八进制数 |
\xhh |
hh 的十进制值 |
表示\(1\sim2\)位十六进制数 |
转义序列不但可以作为字符常量,也可以同其他字符一样出现在字符串中。例如,程序中的abede \n
字符串中含有\(6\)个字符,最后一个为换行符, \tx=
中的首字符为水平制表符,当输出它时将使光标后移8个字符位置。
一个字符用于显示输出时,将输出字符本身或体现出相应的控制功能;当它在表达式中参加整数运算时,将使用它的 ASCII 码值。
例2.1 字符常量的使用方式
//ex2_1.cpp
#include<iostream>
using namespace std;
int main()
{
char ch='H'; //语句1
int x=ch-2; //语句2
if(ch>'C') //语句3
cout<<ch<<'>'<<'C'<<endl;
cout<<"There are "<<x<<" apples.\n"; //语句4
return 0;
}
语句\(1\)定义字符变量ch
并把字符H
赋给它作为其初值,实际上是把字符H
的 ASCII 码值\(72\)赋给了ch
。
语句\(2\)定义整型变量x
并把表达式ch -2
的值\(70\)赋给它。
语句\(3\)首先进行ch>'C'
的比较,实际上是取出各自的值(即对应的 ASCII 码)进行比较,H
的 ASCII 码值\(72\)大于C
的 ASCII 码值\(67\),因此条件成立,执行其后的输出语句,向屏幕输出H>C
。
语句\(4\)输出一个字符串并且使光标移到下一行的开始位置处。
注意:由于语句
using namespace std;
声明可使用名字空间std
中的所有标识符,包括cout
,因此就不必像例\(1.1\)那样在cout
前加上std::
修饰了。
程序的执行结果为:
H>C
There are 70 apples.
整型常量
整型常量就是整型常数,简称整数,它有十进制、八进制和十六进制\(3\)种表示方式。
1.十进制整数
十进制整数以正号(\(+\))或负号(\(-\))开头,由首位非\(0\)的一串十进制数字组成。若以正号开头则为正数,若以负号开头则为负数,若省略正负号,则默认为正数。例如\(0,+123,-456,789\)等都是十进制整数。
整数在计算机中是有表示范围的,因此一个整数在程序中使用时会受到大小的限制。当一个十进制整数大于等于\(-2147483 648\)(即\(-2^{31}\)),同时小于等于\(2 147 483 647\)(即\(2^{31}-1\))时,系统将其看作是整型常量;当在\(2147483 648 ~4 294 967 295\)即\(2^{32}-1\)范围之内时,则被看作是无符号整型常量;当超过上述两个范围时,则无法用C++整数类型表示的数,只有把它用实数(即带小数点的数)表示才能够被有效地存储和处理。
2.八进制整数
八进制整数以数字\(0\)开头,后面接若干个八进制数字(借用十进制数字中的\(0~7\))。八进制整数前面不带正负号,全部默认为正数。如\(0,016,01234\)等都是八进制整数,对应的十进制整数依次为\(0,14\)和\(668\)。
当一个八进制整数大于等于\(0\)同时小千等千\(017777777777\)时,称为整型常量;当大于等于\(020000000000\)同时小于等于\(037777777777\)时,称为无符号整型常量。不要使用超过上述两个范围的八进制整数,因为没有与此相对应的C++整数类型。
3.十六进制整数
十六进制整数以数字\(0\)和字母\(x\)(大、小写均可)开头,后面接若干个十六进制数字(借用十进制数字\(0 \sim 9\),字母\(A \sim F\)或\(a \sim f\))。同八进制整数一样,十六进制整数也全部为正数。如\(0x0,0x55 ,0x1cd,0x50CA\)等都是十六进制整数,对应的十进制整数依次为\(0,85 ,461\)和\(20682\)。
当一个十六进制整数大于等于\(0\)同时小于等于\(0x7FFFFFFF\)时,称为整型常量;当大于等于\(0x80000000\)同时小于等于\(0xFFFFFFFF\)时,称为无符号整型常量。与八进制整数类似,超过上述两个范围的十六进制整数也没有与之相对应的C++整数类型,所以也不能使用它们。
C++中的整型数据除了一般表示方法之外,还允许给它们添加后缀u
或l
。对于任一种进制的整数,若后缀为字母u
(大、小写均可)、则规定它为一个无符号整型(unsigned int
)数,若后缀为字母l
(大、小写均可)、则规定它为一个长整型(long int
)数。在一个整数的末尾,可以同时使用u
和l
,并且对排列无要求。如15U
,0123UL
, Ox1abcL
,1234LU
等都是整数,其类型依次为unsigned int
, unsigned long int
, long int
和unsigned long int
。
实型常量
实型常量简称实数,对应着数学中的实数概念。实型常量有十进制的定点表示和浮点表示两种表示方法。
1.定点表示
定点表示的实数简称定点数,即以小数形式表示实数。定点表示的实数由一个正号或负号(正号可以省略)后接若干个十进制数字和一个小数点组成,这个小数点可以处在任何一个数字位的前面或后面。例如\(.12,1.2,12.,0. 12,-.012\)等都是符合书写规定的定点数。
2.浮点表示
浮点表示的实数简称浮点数,即以指数形式表示实数。浮点表示的实数由一个十进制整数或定点数后接一个字母\(E\)(大、小写均可)和一个\(1\)至\(3\)位的十进制整数组成,字母\(E\)之前的部分称为该浮点数的尾数,之后的部分称为该浮点数的指数,该浮点数的值就是它的尾数乘以\(10\)的指数幂。例如\(3.23E5,+6.35e-6,4E3,0.472E-15,-6. 08E+12,.46E0,96.e24\)等都是合乎规定的浮点数,它们对应的数值分别为:\(3.23×10^5,6.35×10^{-6},4 000,0. 472×10^{-15},-6.08×10^{12} ,0.46,96×10^{24}\)等。
对于一个浮点数,若将它尾数中的小数点调整到最左边第一个非零数字的后面,则称它为规格化)或标准化)浮点数,这有些类似于数学中的科学记数法。例如\(41.6E8\)和\(-0.077E5\)是非规格化的,若将它们分别调整为\(4.16E9\)和\(-7.7E3\)则都是规格化的浮点数。
实型常量分为单精度(float
),双精度(double
)和长双精度(long double
)三类。一般float
型数据在内存中占\(4\)个字节,提供\(7\)位有效数字;double
型数据占\(8\)个子节,提供\(15\)位有效数字;long double
型数据占\(10\)个字节,提供\(19\)位有效数字。对于一个定点数或浮点数,C++自动按一个双精度数(double
型)来存储。若在一个定点数或浮点数之后加上字母\(F\)(大、小写均可),则自动按一个单精度数来存储。例如\(3.14\)和\(3.14f\),虽然数值相同,但分别代表一个双精度数和一个单精度数,同样,\(-2.78E5\)为一个双精度数,而\(-2.78E5F\)为一个单精度数。
枚举常量
枚举常量是枚举类型中定义的值,即枚举值。枚举类型属于用户定义类型,用关键字enum
表示,因此又称为enum
类型。用户通常利用枚举类型定义程序中需要使用的一组相关符号常量。声明枚举类型的语法格式为:
enum<类型名>{<枚举值表>};
其中,enum
是关键字,指出要定义的是枚举类型。<类型名>
是标识符,即由用户给出的具体枚举类型名。<枚举值表>
包含多个枚举值,它们用逗号分隔开,每个枚举值就是一个枚举常量。枚举值有两种定义形式:一是<值名>
,二是<值名>=<整型常量>
。例如:
enum color{RED=1,YELLOW,BLUE};
关于enum
类型有四点说明:
(1)一个enum
类型实际上是int
类型的一个子集,其每一个枚举值代表一个整数。
(2)\(n\)个枚举值全部未赋常量值时,它们自左至右分别与整数\(0,1 ,…,n-1\)对应。
(3)若第\(i\)个枚举值赋常量值为\(m\),则其未赋常量值的后续枚举值分别与整数\(m+1,m+2,…\)对应,直到下一个赋了值的枚举值或结束。因此,为枚举值所赋的整型常量值应从左至右递增。在上面的例子中,YELLOW
与整数\(2\)相对应,BLUE
与整数\(3\)相对应。
(4)枚举类型的声明也可作为成组声明若干整型符号常量的方法。也就是说,把每个要声明的符号常量作为一个枚举值,将各个枚举值合在一起定义成一个枚举类型。
由于枚举类型属于用户定义数据类型,一旦枚举类型被定义后就可以使用它来定义变量,例如:
enum color c1,c2,c3;
其中,关键字enum
可以省略,color
是已经定义的枚举类型,变量c1,c2,c3
的取值可以是枚举值RED,YELLOW,BLUE
中的任意一个。
变量
变量是程序中用于存储信息的单元,它对应于某个内存空间。在定义变量时,需要说明变量的名字和数据类型。这些信息将告诉编译器要为变量分配多少内存空间,以及变量中要存储什么类型的值。由于变量名可以代表其存储空间,因此程序能够在变量中存储值和取出值。
变量的定义
变量的定义是通过变量声明语句来实现的,变量声明语句的一般格式为:
[<存储类>]<类型名><变量名>[=<处置表达式>],...;
<存储类>
有四种,它们分别是auto
、register
、static
、extern
,有关存储类的知识稍后介绍。默认的存储类是auto
。
<类型名>
为已存在的一种数据类型名称,如char
、short
、int
、long
、float
、double
等基本数据类型名,或者用户定义的数据类型名。
<变量名>
是用户定义的一个标识符,用来表示一个变量,该变量可以通过后面的可选项赋予一个值,称为给变量赋初值,也叫作对变量进行初始化。若变量名后不带有初值表达式,则不为变量赋予任何值,此时的变量值不确定。
变量名的命名遵循如下规则:
(1)是一个合法的C++标识符;
(2)不能是C++关键字。
<初值表达式>
是一个表达式,它的值就是赋予变量的初值。
该语句格式后面使用的省略号表示在一条语句中可以定义多个变量,但各变量定义之间必须用逗号分开。
下面是几个变量定义语句示例:
int a,b;
char ch1='a',ch2='A';
int x=a+2*b;
double d1,d2=3.14159;
第一条语句定义了两个整型变量a
和b
;
第二条语句定义了两个字符变量ch1
和ch2
,并被分别赋初值为'a'
和'A'
;
第三条语句定义了一个整型变量x
,并赋予表达式a+2*b
的值作为初值;
第四条语句定义了两个双精度变量,分别为d1
和d2
,其中d2
被赋予初值3.14159
。
例2.2
如果要计算一个圆的周长和面积,则圆的半径、周长和面积都需要设定为变量。假定分别用radius
,girth
和area
标识符表示,它们的类型均应为实数型,本例使用双精度型。
//ex2_2.cpp
#include<iostream>
using namespace std;
int main()
{
double radius; //定义变量radius
cin>>radius; //从键盘输入一个圆的半径
double girth=2*3.14159*radius; //计算周长表达式的值赋给变量girth
double area=3.14159*radius*radius; //计算周长表达式的值赋给变量area
cout<<"radius = "<<radius<<endl;
cout<<"girth = "<<girth<<endl;
cout<<"area = "<<area<<endl;
return 0;
}
在程序的主函数中,第一条语句定义了变量radius
,由于没有给它赋初值,所以其值是不确定的;
第二条语句从键盘输人一个常数给半径radius
,输入的常数可以是整数,也可以是定点数或浮点数,系统将自动把它转换为一个双精度数后再赋给radius
;
第三条和第四条语句分别计算出赋值号右边表达式的值,再分别赋给变量girth
和area
;
第五至七条语句依次向屏幕输出圆的半径、周长和面积。
假定程序运行后从键盘上输人的半径是1.23
,则得到的输出结果为:
radius = 1.23
girth = 7.72831
area = 4.75291
变量的使用方式
C++语言中变量的使用方式比较灵活,下面将介绍一些有关变量使用方面的概念。
1.全局变量和局部变量
全局变量是在所有函数定义、类定义和程序块之外声明的变量。声明全局变量时如果在程序中不对它进行专门的初始化,该变量会被系统自动初始化为\(0\)。在程序的任何一个函数、类或程序块之内均可以访问全局变量。
局部变量是在某个函数定义、类定义或程序块之内声明的变量。局部变量只能在声明它的函数、类或程序块中被访问。
例2.3 全局变量和局部变量的使用
//ex2_3.cpp
#include<iostream>
using namespace std;
int x;
int main()
{
int y;
y=x+2;
cout<<"y = "<<y<<endl;
return 0;
}
上述程序中的变量x
是全局变量,它在所有函数和程序块之外被声明,但没有进行初始化,所以系统默认地将其初始化为\(0\)。
变量y
是局部变量,它在main()
函数中被声明,因此只能在该函数中被访问。声明局部变量y
时也没有进行初始化,与与全局变量不同的是,系统并不给它赋默认值,没有初始化的局部变量中保存者一个不确定的值。通过表达式y=x+2
可以给变量y
赋值。此程序的运行结果为:
y = 2
2.生存期与作用域
生存期是指从一个变量被声明且分配了了内存开始,直到该该变量声明语句失效,它占用的内存空间被释放为止。一个全局变量的生存期从它被声明开始,直到程序结束;一个个局部变量的生存期从它被声明开始,直到包含它的最近的一个程序块结束。
作用域是指变量名可以代表该变量存储储空间的范围。
一般情况下,变量的作用域与其生存期一致,但由于C++语言允许在程序的不同部分为不同变量取同一名字,因此一个变量名的作用域可能小于其生存期。例如,下面代码段:
int f()
{
int a=1,b=5;
if(b>=3)
{
double a=1.0;
b=2;
}
return a;
}
其中,int
型变量a
的生存期是\(3 \sim 10\)行,double
型变量a
的生存期是\(6 \sim 8\)行。int
型变量a
的作用域却只能是\(3 \sim 5\)行和\(9 \sim10\)行;\(6 \sim 8\)行范围内的int
型变量a
虽然被完好地保存着,但却不能使用,即在\(6 \sim 8\)行范围内int
型变量a
是不起作用的。
3. 变量的存储类属性
在C++中变量还可以按存储分配方式的不同被划分为\(4\)种不同的存储类别,它们分别是:
(1)auto
变量:用关键字auto
声明的局部变量称为自动变量。auto
为变量声明时的默认存储类别,即在变量定义时,如果不显式标明存储类别,则系统自动按auto
变量处理。auto
变量所占用存储空间的分配和释放工作将由系统自动完成。
(2)regiter
变量:用关键字regiter
声明的局部变量称为寄存器变量。regiter
变量可能以寄存器作为其存储空间。声明寄存器变量时,关键字register
的作用只能是建议(而不是强制)系统使用寄存器,当寄存器不够用时,该变量仍然按自动变量处理。
(3)static
变量:用关键字static
声明的变量称为静态变量。任何静态变量的生存期将延续到整个程序的终止。与全局变量样,为静态变量分配的存储空间在整个程序运行过程中不再被释放;如果静态变量未被赋初值,系统将自动为其赋初值为\(0\)。
(4)extern
变量:用关键字extern
声明的变量称为外部变量。变量一旦被声明为外部变量,系统就不必像一般变量那样为其分配内存,因为该变量已在这一局部的外面被定义。外部变量一般用于多个文件组成的程序中,有些变量在多个文件中被声明,但却是指同一变量。标明某一变量为外部变量可以避免为其重复分配内存。
4. typedef类型说明
使用关键字typedef
可以为已有类型名定义一个新类型名。其语法格式为:
typedef<已有类型名><新类型名>
例如:
typedef double profit; //为double定义新类型名profit
typedef int integer; //为int定义新类型名integer
profit a; //等价于double a;
integer b; //等价于int b;
typedef
类型说明并没有真正地定义新的数据类型,它只是相当于给某个已有的数据类型起了一个别名。在规模较大的程序中为了提高代码可读性常采用这种形式。
符号常量声明语句
符号常量在使用之前必须先进行定义。符号常量定义语句同变量定义语句类似,其语法格式为:
const<类型名><符号常量名>=<初值表达式>,...;
其中,关键字const
指明这是一条符号常量定义语句,后面跟着符号常量的类型名,接着是符号常量名,它是一个用户定义的标识符,符号常量名之后为一个赋值号和一个初值表达式。注意,必须在声明符号常量的同时为其显式赋初值。该语句也可以定义多个符号常量。
系统执行符号常量定义语句时,需要依次为每个符号常量分配存储单元并赋初值。一个符号常量定义后,它的值就是定义时所赋予的初值,作为常量,这个值以后将始终保持不变,因为系统只允许读取它的值,而不允许再次向它赋值。另外,在符号常量定义语句中,若<类型名>
为int
,则int
可省略。
下面给出几条符号常量定义语句的例子:
const int a=5,b=a*4;
const double pai=3.14159;
第一条语句定义了两个整型符号常量a
和b
,并使它们的初值分别为\(5\)和\(20\);
第二条语句定义了一个双精度符号常量pai
,用它表示圆周率\(π\)的值\(3.141 59\)。
第一条语句中的int
可以省略不写。
C++关键字中的true
和fale
就是系统预先定义的两个符号常量,它们的值分别为\(1\)和\(0\)。使用符号常量往往可以提高程序的可读性和可维护性。由于符号常量和变量同样要求系统为其分配内存单元,所以可以把符号常量视为一种不允许赋值改变的或只读不写的变量,称其为const
变量。
运算符和表达式
运算符和表达式的概念
C++语言中的运算符又称为操作符,是用来对数据进行运算的符号,运算中所需要的数据称为操作数或运算分量。由一个或多个操作数与操作符连接而成的有效运算式称为表达式。表达式还能以运算分量的角色出现在运算中从而组成新的表达式。任何表达式都有一个运算结果。
C++语言中的运算符可以根据其运算分量个数的多少分为单目(或一元)运算符、双目(或二元)运算符和三目(或三元)运算符\(3\)类。
一般情况下,单目运算符位于分量之前,例如要对某个变量x
取相反数可以表示为-x
,这里的-
符号就是一个单目运算符,用在x
的前面;
双目运算符一般位于两个运算分量之间,例如把两个数\(a\)和\(b\)相加可以表示为a+b
,位于a
和b
中间的+
号就是双目运算符;
三目运算符只有一个,即为条件运算符?:
,它由两个字符组成,可以把3个运算分量分隔开。
运算符可能是一个字符,也可能由两个或三个字符组成,还有一些运算符是C++关键字。例如,加号(+
)就是一个字符,逻辑与($$
)就是两个字符,左移赋值号(<<=
)就是三个字符,测类型长度运算符(sizeof
)就是一个C++关键字;
运算类型与运算符
同其他的程序设计语言一样,C++也包含多种不同种类的运算。每一种运算与其他运算的区别在于以下\(3\)个方面:
(1)参加运算的运算分量的数量和类型;
(2)运算结果的数据类型;
(3)运算的具体操作。
例如,浮点型乘法运算有两个float
型运算分量,运算结果为float
型,具体操作为两数相乘求积;大于(>
)关系运算有两个int
型(或float
型、char
型等)运算分量,运算结果为true
或false
,具体操作为对两个运算分量进行比较。
C++语言为每种允许的运算提供一种运算符 ,例如整数加法为+
,小于关系运算符为<
,增量运算为++
。为了符合人们的习惯和节省专用符号,有些运算符可以一符多用,即一个运算符对应多种运算。例如,*
一般是作为乘法运算符,同时,它还是单目的取值运算(用于指针类型)的运算符。同一类运算可以组成一种运算类型,凡是具有相同运算分量和结果类型的运算划分为同一类运算,比如算术运算、关系运算、逻辑运算、位运算等。
赋值运算
赋值运算是种双目运算,其形式为:
<变量名>=<表达式>
右运算分量为一个表达式。=
为赋值运算符。左运算分量为与右运算分量类型相同的变量。
赋值运算的具体操作为:先计算右端表达式的值,然后把该值赋给左端变量。
由赋值符号连接左端变量和右端表达式而构成的式子称为赋值表达式。每个赋值表达式都有一个值,这个值就是通过赋值得到的左端变量的值。例如,x=3*15-1
的值就是通过赋值而保存在x
中的值\(44\)。
通常在一个赋值表达式中,赋值号两边的数据类型是相同的,当两边的数据类型不同时,则在赋值前会自动把右边表达式的值转换为与左边变量类型相同的值,然后再把这个值赋给左边变量。例如,在执行x = 10/3.0
时,若x
为int
型变量,则得到的x
值为\(3\),它是将右边计算得到的double
型值舍去小数部分,只保留整数部分\(3\)的结果。再如,执行y=40
时,若y
为double
型变量,则首先把\(40\)转换为双精度数\(40.0\)后再赋给y
。
注意:当把一个实数值赋给一个整型量时,将丢失小数部分,获得的只是整数部分,它是实数的一个近似值。
在一个赋值表达式中可以使用多个赋值号实现给多个变量赋值的功能。例如,在执行x=y=z=0
时就能够同时给x
,y
和z
赋值为\(0\)。由于赋值号的运算顺序是从右向左,所以实际的赋值过程为:首先把\(0\)赋给z
,得到子表达式z = 0
的值为z
的值\(0\),接着把这个值赋给y
,得到子表达式y=z=0
的值为y
的值\(0\),最后把这个值赋给x
,使x
的值也为\(0\)。整个表达式的值也就是x
的值\(0\)。
赋值号也可以使用在常量和变量的声明语句中,用于给符号常量和变量赋初值。但这里的赋值号只起到赋初值的作用,并不构成赋值表达式。
C++中还有许多复合赋值运算符,它们的含义为:将右边表达式的值同左边变量的值进行相应运算后,再把这个运算结果赋给左边的变量,该复合赋值表达式的值也就是保存在左边变量中的值。例如,执行x+=2
时,就是把x
的值加上\(2\)后再赋给x
,它与执行x=x+2
表达式的计算是等价的,若x
的值为\(5\),则计算后得到的x
的值为\(7\),它也是这个表达式的值。
对于任一种赋值运算,其赋值号或复合赋值号左边必须是一个左值。左值是指具有对应的可由用户访问的存储单元,并且能够由用户改变其值的量。例如,一个变量就是一个左值,因为它对应着一个存储单元,并可由用户通过变量名访问和改变其值;一个字面常量就不是一个左值,因为它不存在供用户访问并能改变其值的存储单元;一个通过const
语句定义的符号常量也不是一个左值,因为虽然用户能访问它,但不能改变它的值;一般的算术表达式(如x*2+5
)也不是一个左值,因为它的值只能随时被使用,不能再被访问和改变。由此可知:表达式(x+5) = 10
是非法的,因为赋值号左边的(x+5)
是一个值,而不是一个左值,常量\(10\)无法赋给它。不是左值的量被称为右值。
一个赋值表达式的结果实际上是一个左值,即赋值号左边的变量。例如,x=y- 2
的值就是被赋值后的x
,它是一个左值,代表者对应存储单元中的值。同样,x *=y
的结果也是一个左值,即x
。表达式(x+=5)*=2
是合法的,其结果为左值x
,若x
的原值为\(2\),则最后得到的x
值为\(14\)。
算术运算符和算术表达式
算术运算是指int
型、float
型、double
型(也包括char
型)的数值类数据计算后,得到同一类型数据的运算。算术运算中所使用的运算符称为算术运算符。
单目算术运算符包括:-
(单)、++
(增量)和--
(减量)。
单减运算的格式为:-<运算分量>
单减运算相当于对运算分量取相反数,例如:-a
、-(x+y)
。
增量运算有两种形式。
前缀增量:++<运算分量>
后缀增量:<运算分量>++
前缀增量和后缀增量的区别是:如果++i
和i++
作为表达式又参加其他运算的话,前者是先令i
加\(1\),然后再参加其他运算:后者则是先令i
参加其他运算,然后再令i
加\(1\)。减量运算的格式和操作与增量运算类似。
例如,在下面各表达式中,如果:int
型变量x
的初始值为\(10\),则:
++x //表达式的值为增1,后的x值,即11
x++ //x的值为11,但表达式的值仍为10
y=x++ //x的值为11,y的值为10
y=--x //x的值为9,y的值为9
y=2*x++ //x的值为11,y的值为20
双目算术运算符包括:+
(加)、-
(减)、*
(乘)、/
(除)和%
(取余)。它们的含义与数学上相同。
该类运算的运算分量为任一种数值类型,即任一种整数类型和任一种实数类型
由算术运算符(包括单目和双目)连接运算分量而组成的式子称为算术表达式。每个算术表达式的值为一个数值,其类型按照以下规则确定:
(1)当参加运算的两个运算分量均为整型时(但具体类型可以不同,如一个为int
型,另一个为char
型),则运算结果为int
型。
(2)当参加运算的两个运算分量中至少有一个是单精度型,并且另一个不是双精度型时,则运算结果为float
型。
(3)当参加运算的两个运算分量中至少有一个是双精度型时,则运算结果为双精度型。
例如,在下面各表达式中,如果int
型变量x
和y
的初始值分别为\(29\)和\(6\),则:
x-y //表达式的值为23
x/8 //表达式的值为3
x/y+5 //表达式的值为9
10-x%y //表达式的值为5
-x/5 //表达式的值为-5
如果将y
看成double
型变量并赋值为\(6.0\),则:
x-y //表达式的值为23.0
x/y //表达式的值为4.83333
若要使两个整数相除得到一个实数,则必须将其中之一强制转换为实数。例如:
float(y)/24 //表达式的值为0.25
x/double(-8) //表达式的值为-3.625
其中float(y)
和double(-8)
分别表示把括号内的表达式的值强制转换为一一个单精度数和双精
关系运算符和关系表达式
C++语言提供了\(6\)种关系运算符,它们是:
<
(小于)、<=
(小于等于)、>
(大于)、>=
(大于等于)、==
(等于)、!=
(不等于)
这\(6\)种运算符都是双目运算符,用来比较两个运算分量的大小,运算结果为逻辑型值true
或false
(它们分别对应着整数\(1\)和\(0\))。由一个关系运算符连接前后两个数值表达式而构成的式子称为关系表达式,简称关系式。当一个关系式成立时,则计算结果为逻辑值真(true
),否则为逻辑值假(false
)。
关系运算符的使用格式为:
<运算分量><关系运算符><运算分量>
例如,在下面各表达式中,如果int
型变量x
的值为\(2\),double
型变量y
的值为\(1.25\),则:
x==0 //不成立,表达式的值为false
x!=y //成立,表达式的值为true
x++>=3 //不成立,表达式的值为flse,但x的值变为3
y+10<y*10 //成立,表达式的值为true
'a'=='A' //不成立,表达式的值为false
可以将上述\(6\)种关系运算符分为三组:<
和>=
、>
和<=
、==
和!=
,每组中的两个运算符互为反运算,当一种运算的结果为true
时,它的反运算结果为false
。例如,当x>y
成立时,其结果为逻辑值true
;它的反运算x<=y
必然不成立,其结果为逻辑值false
。由反运算构成的式子称为原式的相反式。例如,x>y
和x<=y
就互为相反式。
逻辑运算符和逻辑表达式
C++语言提供了\(3\)种逻辑运算符,它们是:
!
(逻辑非)、&&
(逻辑与)、||
(逻辑或)
其中,!
为单目运算符,&&
和||
为双目运算符。
逻辑运算符的使用规格为:
<逻辑运算符!><运算分量>
<运算分量><逻辑运算符&&或||><运算分量>
在进行逻辑运算操作时,要注意:以\(0\)值为假(即false
),非\(0\)值为真(即true
)。
例如,下面语句段:
int a=1,b=2;
cout<<!a<<"--"<<!(a-b)<<endl;
cout<<a&&b<<"--"<<a&&(a-1)<<endl;
cout<<a||b<<"--"<<a||(b-2)<<endl;
输出结果为:
0--0
1--0
1--1
逻辑非是对运算分量的值取反,若运算分量的值为true
,则运算结果为false
,若运算分量的值为false
,则运算结果为true
;逻辑与的结果是当两个运算分量的值都为true
(或非false
)时,其值为true
,否则为false
;逻辑或的结果是当两个运算分量的值都为false
时,其值为false
,否则为true
。逻辑非、逻辑与、逻辑或的运算规则如表2.3所示。
表2.3 逻辑运算规则
a | b | !a | a&&b | a||b |
---|---|---|---|---|
false | false | true | false | false |
false | true | true | false | true |
true | false | false | false | true |
true | true | false | true | true |
逻辑运算的运算分量是逻辑型数据。逻辑常量、逻辑变量、关系表达式等都是逻辑型数据,由逻辑型数据和逻辑运算符连接而成的式子称为逻辑表达式,简称逻辑式。一个数值表达式也可以作为一个逻辑型数据使用,当值为\(0\)时则认为是逻辑值false
,当值为非\(0\)时则认为是逻辑值true
。总之,任何一个具有\(0\)或非\(0\)取值的式子都可以作为逻辑表达式使用。
例如,在下面各表达式中,如果int
变量x
的值为\(2\),double
型变量y
的值为\(1.25\),则:
x>0&&y>0 //即1&&1,表达式的值为true
x&&false //即1&&0,表达式的值为false
x<-10||x>10 //即0||0,表达式的值为false
x++!=3||y //即1||1,表达式的值为true
位运算
C++提供了\(6\)种位运算符:
双目位运算符:&
(按位与)、1
(按位或)、^
(按位异或)、>>
(按位右移)、<<
(按位左移)
单目位运算符:~
(按位取反)
位运算符的使用格式为:
<运算分量><双目运算符><运算分量>
<单目运算符><运算分量>
(1)&
是按位与运算符,它将两个运算分量的对应二进制位进行与操作。其中,\(0\)和\(0\)与得\(0\),\(0\)和\(1\)与得\(0\),\(1\)和\(0\)与得\(0\),\(1\)和\(1\)与得\(1\)。
(2)|
是按位或运算符,将两个运算分量的对应二进制位进行或操作。其中,\(0\)和\(0\)或得\(0\),\(0\)和\(1\)或得\(1\),\(1\)和\(0\)或得\(1\),\(1\)和\(1\)或得\(1\)。
(3) ^
是按位异或运算符,它将两个运算分量的对应二进制位进行异或操作。其中,\(0\)和\(0\)异或得\(0\),\(0\)和\(1\)异或得\(1\),\(1\)和\(0\)异或得\(1\),\(1\)和\(1\)异或得\(0\)。
(4)>>
是按位右移运算符,由于右移的位数为右边运算分量的值,所以右边运算分量的值必须是一个整数。
(5)<<
是按位左移运算符,由于左移的位数为右边运算分量的值, 所以右边运算分量的值必须是一个整数。
(6)~
是按位取反运算符,它将运算分量的对应二进制数的每一位进行取反操作。其中,\(0\)取反得\(1\),\(1\)取反得\(0\)。
例如,在下面各表达式中,如果char
型变量x
的二进制值为\(00011000\)(即十进制数\(24\)),char
型变量y
的二进制值为\(00100100\)(即十进制数\(36\)),则:
x<<2 //表达式的二进制值为0100000
y>>3 //表达式的二进制值为0000100
~x //表达式的二进制值为1100111
x&y //表达式的二进制值为00000000
x|y //表达式的二进制值为01011100
x^44//(十进制数)//表达式的二进制值为00110100
其他运算
C++中运算的种类十分丰富,除了以上介绍的算术运算、关系运算、逻辑运算等外,一些通常看来不是运算的操作,在C++中也被列为运算,并提供了相应的运算符。下面分别对这些运算符进行简单的介绍。
1.条件运算符
条件运算是C++中唯一的三目运算,与其对应的运算符?:
称为条件运算符。条件运算符的使用格式为:
<表达式1>?<表达式2>?<表达式3>
当计算由条件运算符构成的表达式时,首先计算<表达式1>
,若其值非\(0\),则计算出<表达式2>
的值,并用这个值作为整个表达式的值;若<表达式1>
的值为\(0\),则计算出<表达式3>
的值,并用这个值作为整个表达式的值。
例如,下面各表达式:
x=a>b ? : b //若a>b为真则将a的值赋给x,否则将b的值赋给x
cout<<(cnt ? "nonzero" : "zero") //若cnt的值非0则输出"nonzero",否则输出"zero"
2.逗号运算符
C++中使用逗号运算符指明对多个表达式进行顺序求值。逗号运算符的使用格式为:
<表达式1>,<表达式2>,...,<表达式n>
其中,每个逗号都称为逗号运算符,整个式子称为逗号表达式。上述逗号表达式的求值步骤为:从左向右依次计算<表达式1>
、<表达式2>
、\(\cdots\)、<表达式n>
的值:将<表达式n>
(即最右端的表达式)的值作为整个逗号表达式的值。
例如,若下面表达式中使用的int
型变量x
、y
和t
都已进行过声明,则:
y=(t=x,x+=1,t)
是一个赋值表达式,赋值运算符的右运算分量是一个逗号表达式。计算该逗号表达式时,首先将\(x\)的值赋给\(t\),接着将\(x\)增\(1\),最后将\(t\)的值作为整个逗号表达式的值。也就是说,上述赋值表达式最终将\(t\)的值赋给了变量\(y\)。
3. sizeof 运算符
使用运算符sizeof
可以进行字长提取操作,因此sizeof
运算符又称为字长提取符,它的使用格式为:
sizeof(<运算分量>)
其中,sizeof
为关键字;<运算分量>
既可以是一个类型名,也可以是一个变量名。
子长提取运算的结果为一个整数,该整数表示指定的类型或变量的字节长度,即在内存中占用的字节(Byte)数。例如,在下面各表达式中,如果a
、b
都是int
型变量,则:
sizeof(a) //表达式的值为4
sizeof(b) //表达式的值为4
sizeof(int) //表达式的值为4
sizeof(char) //表达式的值为1
注意:得出上述结果的前提条件是,假设char
型和int
型变量在内存中分别占用\(2\)个和\(4\)个字节,因此在不同的机器系统上可能得到不同的结果。
4.圆括号运算符
C++中不仅将圆括号()
归为运算符,而且根据不同的使用方式,可以对圆括号运算符的功能做出以下\(3\)种不同的解释:
(1)圆括号用于函数调用。其格式为:
<函数名>(<实参表>)
例如,下面各表达式:
sqrt(2)
strcpy(d,s)
myfunc(a,b)
其中,圆括号运算符跟在函数名的后面,表示进行函数调用;圆括号中是函数的实际参数列表。有关函数的具体内容请参见第\(5\)章。
(2)圆括号用于强制类型转换。其格式为:
(<类型名>)<表达式>
例如,下面代码段:
int a=1,b=3;
cout<<a/b<<"--"
<<(double)a/b
<<endl;
输出结果为:
0--0.333333
具有相同数据类型的运算分量进行算术运算的结果值仍为该类型。由于上述变量a
和b
均为int
型,因此表达式a/b
的结果值也为int
型,即只取商的整数部分。要想使a/b
得到较为准确地小数结果,必须将变量a
或b
中的一个显式地转换为实数型(a
和b
都转换也可以)。这样的数据类型转换称为强制类型转换,即把要转换到的目标数据类型名用圆括号括起来,置于某个变量之前。上例中将a
由int
型强制转换为double
型。
又例如,在下面各表达式中,若int
型变量n
的值为\(80\),char
型变量c
的值为'd'
(对应的ASCⅡ码值为\(100\)),则:
(float)n //表达式的值为float型80.0
(char)n //表达式的值为char型'P'
(int)c //表达式的值为int型100
(3)圆括号用于类型构造。其格式为:
<类型名>(<表达式>)
类型构造是指使用圆括号中<表达式>
的值来构造一个具有目标数据类型的值,要构造的目标数据类型由<类型名>
指定。
例如,下面代码段:
double d=3.25;
int n=int(d); //将double型变量d构造为int型
char c=char(65); //将65构造为char型变量
cout<<n<<" "<<c<<endl;
输出结果为:
3 A
从上例中可以看出,类型构造在功能上等价于强制类型转换。
<类型名>
也可以是用户定义数据类型(如类类型),用户定义数据类型的默认值由该类型的构造函数给出。有关用户定义数据类型的具体内容请参见第\(6\)章。
除此之外,考虑到内容的先后顺序,还有一些C++运算符没有在这里介绍。它们是:
(1)数组下标运算符:[]
(下标),请参见第\(4\)章。
(2)指针运算符:*
(取地址)和&
(值引用),请参见第\(4\)章。
(3)动态存储分配运算符:new
(分配)和delete
(释放),请参见第\(4\)章。
(4)作用域限定运算符:::
(类域或全局域),请参见第\(6\)章。
有关它们的具体内容请读者参阅相应的章节。
优先级和结合性
C++中运算符的种类相当丰富,每个运算符的使用方法和操作方式也各不相同。表达式可以由多种不同的运算符连接运算分量而构成。C++语言为每一种运算符规定了相应的优先级,以确定它们在表达式中的运算顺序。例如,表达式:
6+3*4/2-2
将按照如下顺序进行计算:
(1)\(3 \times 4 \rightarrow 12\)
(2)\(12/2 \rightarrow 12\)
(3)\(6+6 \rightarrow 12\)
(4)\(12-2 \rightarrow 10\)
该表达式的最终结果值为\(10\),这表明在C++中运算符*
(乘)和/
(除)的优先级高于运算符+
(加)和-
(减)的优先级,因此先计算乘除法,后计算加减法;另一方面,运算符*
(乘)和/
(除)的优先级相同(运算符+
、-
的优先级也相同),所以它们将按从左向右的顺序被计算。
使用圆括号(
和)
将子表达式括起来,可以改变默认的运算符优先级。在求一个表达式的值时,首先要计算所有括号中的子表达式,再用计算的结果代替每个子表达式,然后继续计算。内层括号比外层括号先计算。例如,下面各表达式:
4*5+7*2 //表达式的值为34
4*(5+7*2) //表达式的值为76
4*((5+7)*2) //表达式的值为96
运算符不仅具有优先级,还具有结合性。当优先级相同的运算符相邻地出现在一个表达式中时是按照从左向右的顺序进行计算,还是按照从右向左的顺序进行计算,将取决于运算符的结合性。
例如,算术运算符是左结合的,因此下面的表达式将从左向右进行计算:
a+b-c+d //左结合的
即先把a
和b
相加,然后再减去c
,最后加上d
。
又例如,赋值运算符是右结合的,因此下面的表达式将从右向左进行计算:
a=b=c=d //右结合的
即先把d
赋值给c
,然后将结果赋值给b
,最后将结果赋值给a
。
根据运算符的优先级和结合性,可以将表达式的计算顺序规则总结为以下\(3\)条:
(1)优先计算带有括号的子表达式;
(2)在没有括号的部分,依照运算符优先级,由高到低进行计算;
(3)具有相同优先级的运算符,按照结合性规定,依次进行计算。
表2.4给出了C++运算符的优先级和结合性。表中将全部运算符分成\(17\)个优先级,并用数字标出,优先级数字越小,表示运算符优先级越高。具有同一优先级数字的运算符,优先级相同。从表中还可看出,单目运算符、赋值运算符和复合赋值运算符是右结合的,其余所有运算符都是左结合的。
表2.4 C++运算符的优先级与结合性
优先级 | 运算符 | 功能 | 用法 | 结合性 |
---|---|---|---|---|
1 | :: |
类域 | class_name::member |
左结合 |
1 | :: |
全局域 | ::name |
左结合 |
2 | . |
成员选择 | object.member |
左结合 |
2 | -> |
成员选择 | pointer->member |
左结合 |
2 | [] |
下标 | pointer[expr] |
左结合 |
2 | () |
函数调用 | expr(expr_list) |
左结合 |
2 | () |
类型构造 | type(expr_list) |
左结合 |
2 | ++ |
后缀增量 | lvalue++ |
右结合 |
2 | -- |
后缀减量 | lvalue-- |
右结合 |
3 | sizeof |
变量长度 | sizeof expr |
右结合 |
3 | sizeof |
类型长度 | sizeof(type) |
右结合 |
3 | ++ |
前缀增量 | ++lvalue |
右结合 |
3 | -- |
前缀减量 | --lvalue |
右结合 |
3 | ~ |
按位取反 | ~expr |
右结合 |
3 | ! |
逻辑非 | !expr |
右结合 |
3 | - |
单目减 | -expr |
右结合 |
3 | + |
单目加 | +expr |
右结合 |
3 | & |
取地址 | &expr |
右结合 |
3 | * |
值引用 | *expr |
右结合 |
3 | new |
动态分配 | new type |
右结合 |
3 | delete |
变量释放 | delete pointer |
右结合 |
3 | delete |
数组释放 | delete [] poiner |
右结合 |
3 | () |
强制类型转换 | (type)expr |
右结合 |
4 | .* |
指向成员选择 | object.*pointer_to_member |
左结合 |
4 | ->* |
指向成员选择 | pointer->*pointer_to_member |
左结合 |
5 | * |
乘 | expr*expr |
左结合 |
5 | / |
除 | expr/expr |
左结合 |
5 | % |
取余(取模) | expr%expr |
左结合 |
6 | + |
加 | expr+expr |
左结合 |
6 | - |
减 | expr-expr |
左结合 |
7 | << |
按位左移 | expr<<expr |
左结合 |
7 | >> |
按位右移 | expr>>expr |
左结合 |
8 | < |
小于 | expr<expr |
左结合 |
8 | <= |
小于等于 | expr<=expr |
左结合 |
8 | > |
大于 | expr>expr |
左结合 |
8 | >= |
大于等于 | expr>=expr |
左结合 |
9 | == |
等于 | expr==expr |
左结合 |
9 | != |
不等于 | expr!=expr |
左结合 |
10 | & |
按位与 | expr&expr |
左结合 |
11 | ^ |
按位异或 | expr^expr |
左结合 |
12 | ` | ` | 按位或 | `expr |
13 | && |
逻辑与 | expr&&expr |
左结合 |
14 | ` | ` | 逻辑或 | |
15 | ?: |
条件表达式 | expr ? expr : expr |
右结合 |
16 | = |
赋值 | lvalue=expr |
右结合 |
16 | *= |
乘赋值 | lvalue*=expr |
右结合 |
16 | /= |
除赋值 | lvalue/=expr |
右结合 |
16 | %= |
取余赋值 | lvalue%=expr |
右结合 |
16 | += |
加赋值 | lvalue+=expr |
右结合 |
16 | -= |
减赋值 | lvalue-=expr |
右结合 |
16 | <<= |
按位左移赋值 | lvalue<<=expr |
右结合 |
16 | >>= |
按位右移赋值 | lvalue>>=expr |
右结合 |
16 | &= |
按位与赋值 | lvalue&=expr |
右结合 |
16 | ` | =` | 按位或赋值 | `lvalue |
16 | ^= |
按位异或赋值 | lvalue^=expr |
右结合 |
17 | , |
逗号 | expr,expr |
左结合 |
本章小结
本章介绍了C++语言的数据类型、运算符和表达式。
C++中的数据类型大体分成\(3\)类:基本类型、导出类型和用户定义类型。其中基本类型包括:逻辑型、字符型、整型、浮点型和空值型。在基本类型名称前面加上类型修饰符可以构成基本类型的派生类型。
C++程序中的数据可分为常量和变量两大类。常量是指在程序执行过程中值不改变的量,分为字面常量和符号常量。变量是程序中用于存储信息的单元,对应于某个内存空间。使用变量时应遵循“先声明,后使用”的原则,并注意全局与局部,生存期与作用域及存储类属性等概念。
使用typedef
可以为已有类型名定义一个别名。const
定义语句可以用来定义符号常量。
C++中运算符的种类十分丰富,包括:算术运算符、赋值运算符、关系运算符、逻辑运算符和位运算符等。由运算符将运算分量连接起来便组成了表达式。表达式的值是按照C++中运算符优先级和结合性规则计算出来的。
习题2
选择题
1.在\(16\)位计算机中,一个int
型数据所占用的内存长度为____字节。
A)2
B)4
C)6
D)8
2.下列字符常量的写法中,错误的是____。
A)'\105'
B)'*'
C)'\4f'
D)'\a'
3.下列选项中属于flaot
类型的字面常量是____。
A)3.14
B)3.14f
C)3.14L
D)0.0314E2
4.下列十六进制整型常量的写法中,错误的是____。
A)0xaf
B)2f0x
C)0X1b
D)0xAE
5.下列变量名的写法中,正确的是____。
A)byte-size
B)CHINA
C)double
D)A+a
6.已知枚举类型定义语句为:
enum Token{NAME,NUMBER,PLUS=5,MINUS,PRINT=10};
则下列说法中错误的是____。
A)枚举常量NAME
的值为\(1\)
B)枚举常量NUMBER
的值为\(1\)
C)枚举常量MINUS
的值为\(6\)
D)枚举常量PRINT
的值为\(10\)
7.下列C++运算符中,优先级最高的是____。
A)+
(双目)
B)*
(单目)
C)<=
D)*=
8.下列关于C++运算符结合性的说法中,正确的是____。
A)赋值运算符是左结合的
B)复合赋值运算符是左结合的
C)单目运算符是左结合的
D)双目运算符是左结合的
9.下列关于左值(lvalue
)的说法中,错误的是____。
A)在程序中左值可以被用户访问和修改
B)赋值或复合赋值运算符的左运算分量必须是左值
C)字面常量的值不能被用户改变,因此字面常量是左值
D)变量在内存中有对应的存储单元,因此变量是左值
10.下列关于类型转换的说法中,错误的是____。
A)如果a
为int
型变量,b
为char
型变量,则a+b
的值为int
型
B)如果a
为float
型变量,b
为int
型变量,则a-b
的值为float
型
C)如果a
为double
型变量,b
为float
型变量,则a*b
的值为double
型
D)如果a
为int
型变量,b
为int
型变量,则a/(double)b
的值为int
型
填空题
1.C++中的数据类型大体上可以分成三类,它们是____、____ 和 ____ 。
2.C++程序中的数据可分为____和____两大类。其中,____是指在程序执行过程中值不改变的量。____是程序中用于存储信息的单元,并对应于某个内存空间。
3.写出下列代码段中表达式的值:
(1)
double x=2.5,y=4.7;
int a=7;
x+a%3*(int)(x+y)%2/4;
表达式的值为____
(2)
int a,b;
a=2,b=5,a++,b++,a+b;
表达式的值为____
4.与公式\(\frac{1}{2}(ax+\frac{a+x}{4a})\)等价的C++表达式为____。
5.写出执行完下列代码段之后指定变量的值:
bool x=true,y=false,z=false;
x=x&&y||z;
y=x||y&&z;
z=!(x!=y)||(y==z);
则x
= ____ ,y
= ____ ,z
=____。
编程题
1.编写程序,输出各种基本类型及其派生类所占用的字节长度,请使用sizeof
运算符。
2.根据以下函数关系,对于给定的每个x
的值,求出y
的值。请编写此程序。
y=x+1 //其中,x=-5,1
y=x*(x+2) //其中,x=2,10
y=2*x //其中,x=3.5,123.456
3.已知一个三角形中三条边的长度分别为\(a\)、\(b\)和\(c\),编写程序利用公式\(\sqrt{s(s-a)(s-b)(s-c)}\)求出三角形的面积,其中\(s=(a+b+c)/2\)。要求边长\(a\)、\(b\)、\(c\)的值由键盘输入,并确保任意两边的长度之和大于等于第三条边。
习题参考答案
选择题
1.A
2.C
3.B
4.B
5.B
6.A
7.B
8.D
9.C
10.D
填空题
1.基本类型、导出类型、用户定义类型
2.常量、变量、常量、变量
3.(1)\(2.5\);(2)\(9\)
4.
(a*x+(a+x)/(4*a))/2
5.false
、false
、true
编程题
1.代码如下:
#include<iostream>
using namespace std;
int main(){
cout<<"short int size = "<<sizeof(short int)<<endl;
cout<<"unsigned short int size = "<<sizeof(unsigned short int)<<endl;
cout<<"int size = "<<sizeof(int)<<endl;
cout<<"unsigned int size = "<<sizeof(unsigned int)<<endl;
cout<<"long int size = "<<sizeof(long int)<<endl;
cout<<"unsigned long int size = "<<sizeof(unsigned long int)<<endl;
cout<<"char size = "<<sizeof(char)<<endl;
cout<<"unsigned char size = "<<sizeof(unsigned char)<<endl;
cout<<"float size = "<<sizeof(float)<<endl;
cout<<"double size = "<<sizeof(double)<<endl;
cout<<"long double size = "<<sizeof(long double)<<endl;
cout<<"void size = "<<sizeof(void)<<endl;
return 0;
}
运行结果如下:
short int size = 2
unsigned short int size = 2
int size = 4
unsigned int size = 4
long int size = 4
unsigned long int size = 4
char size = 1
unsigned char size = 1
float size = 4
double size = 8
long double size = 16
void size = 1
注:对void使用sizeof是不准确的,有警告,运行结果仅对本人编译器版本有效;
2.代码如下:
#include<iostream>
using namespace std;
int main(){
if(1){
int x,y;
cout<<"y=x-1"<<endl;
cout<<"x=-5: y="<<(y=(x=-5)-1)<<endl;
cout<<"x=1: y="<<(y=(x=1)-1)<<endl;
cout<<"y=x*(x+2)"<<endl;
cout<<"x=2: y="<<(y=(x=2)*(x+2))<<endl;
cout<<"x=10: y="<<(y=(x=10)*(x+2))<<endl;
}
if(1){
double x,y;
cout<<"y=2*x"<<endl;
cout<<"x=3.5: y="<<(y=2*(x=3.5))<<endl;
cout<<"x=123.456: y="<<(y=2*(x=123.456))<<endl;
}
return 0;
}
运行结果如下:
y=x-1
x=-5: y=-6
x=1: y=0
y=x*(x+2)
x=2: y=8
x=10: y=120
y=2*x
x=3.5: y=7
x=123.456: y=246.912
3.代码如下:
#include<cstdio>
#include<cmath>
int main(){
double a,b,c,s;
scanf("%lf %lf %lf",&a,&b,&c);
s=(a+b+c)/2;
printf("%lf",sqrt(s*(s-a)*(s-b)*(s-c)));
return 0;
}
输入样例:
3 4 5
输出样例:
6.000000