条件运算符Conditional operator ( ? )
条件运算符计算一个表达式的值并根据表达式的计算结果为真true或假false而返回不同值。它的格式是:
如果条件condition 为真true,整个表达式将返回esult1,否则将返回result2。
7==5 ? 4 : 3 | 返回3,因为7不等于5. |
7==5+2 ? 4 : 3 | 返回4,因为7等于5+2. |
5>3 ? a : b | 返回a,因为5大于3. |
a>b ? a : b | 返回较大值,a 或b. |
位运算符Bitwise Operators ( &, |, ^, ~, <<, >> )
位运算符以比特位改写变量存储的数值,也就是改写变量值的二进制表示:
op | asm | Description |
---|---|---|
& | AND | 逻辑与 Logic AND |
| | OR | 逻辑或Logic OR |
^ | XOR | 逻辑异或Logical exclusive OR |
~ | NOT | 对1取补(位反转)Complement to one (bit inversion) |
<< | SHL | 左移Shift Left |
>> | SHR | 右移Shift Right |
sizeof()
这个运算符接受一个输入参数,该参数可以是一个变量类型或一个变量自己,返回该变量类型(variable type) 或对象(object)所占的字节数
1.4 操作符/运算符(Operators)
前面已经学习了变量和常量,我们可以开始对它们进行操作,这就要用到C++的操作符。有些语言,很多操作符都是一些关键字, 比如add, equals等等。C++的操作符主要是由符号组成的。这些符号不在字母表中,但是在所有键盘上都可以找到。这个特点使得C++程序更简洁,也更国际化。运算符是C++语言的基础,所以非常重要。
你不需要背下所有这一小节的内容,这些细节知识仅供你以后需要时参考 。
赋值Assignation (=)
赋值运算符的功能是将一个值赋给一个变量。
a = 5;
将整数5赋给变量a。= 运算符左边的部分叫做lvalue (left value),右边的部分叫做rvalue (right value)。lvalue 必须是一个变量,而右边的部分可以是一个常量,一个变量,一个运算(operation)的结果或是前面几项的任意组合。
有必要强调赋值运算符永远是将右边的值赋给左边,永远不会反过来。
a = b;
将变量b (rvalue)的值赋给变量a (lvalue),不论a当时存储的是什么值。同时考虑到我们只是将b的数值赋给a,以后如果b的值改变了并不会影响到a的值.
例如:如果我们使用以下代码(变量值的变化显示在绿色注释部分):
// 赋值符号例子 #include <iostream> using namespace std; int main () { int a, b; // a:?, b:? a = 10; // a:10, b:? b = 4; // a:10, b:4 a = b; // a:4, b:4 b = 7; // a:4, b:7 cout << "a:"; cout << a; cout << " b:"; cout << b; return 0; } | a:4 b:7 |
以上代码结果是a的值为4, b的值为7。最后一行中b的值被改变并不会影响到a,虽然在此之前我们声明了a = b; (从右到左规则right-to-left rule)。
C++拥有而其他语言没有的一个特性是赋值符 (=) 可以被用作另一个赋值符的rvalue (或rvalue的一部分) 。例如:
a = 2 + (b = 5);
等同于:
b = 5;
a = 2 + b;
它的意思是:先将5赋给变量b,然后把前面对b的赋值运算的结果(即5)加上2再赋给变量a,这样最后a中的值为7。因此,下面的表达式在C++中也是正确的:
a = b = c = 5; //将5同时赋给3个变量a, b和c。
数学运算符Arithmetic operators ( +, -, *, /, % )
C++语言支持的5种数学运算符为:
- + 加addition
- - 减subtraction
- * 乘multiplication
- / 除division
- % 取模module
加减乘除运算想必大家都很了解,它们和一般的数学运算符没有区别。
唯一你可能不太熟悉的是用百分号(%)表示的取模运算(module)。取模运算是取两个整数相除的余数。例如,如果我们写a = 11 % 3;,变量a的值将会为结果2,因为2是11除以3的余数。
组合运算符Compound assignation operators (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)
C++以书写简练著称的一大特色就是这些组合运算符compound assignation operators (+=, -=, *= 和 /= 及其他) ,这些运算符使得只用一个基本运算符就可改写变量的值:
value += increase; 等同于 value = value + increase;
a -= 5; 等同于 a = a - 5;
a /= b; 等同于 a = a / b;
price *= units + 1; 等同于 price = price * (units + 1);
其他运算符以此类推。例如:
// 组合运算符例子 #include <iostream> using namespace std; int main () { int a, b=3; a = b; a+=2; // 相当于 a=a+2 cout << a; return 0; } | 5 |
递增和递减Increase and decrease
书写简练的另一个例子是递增(increase)运算符 (++)和递减(decrease) 运算符(--)。它们使得变量中存储的值加1或减1。它们分别等同于+=1和-=1。因此:
a++;
a+=1;
a=a+1;
在功能上全部等同,即全部使得变量a的值加1。
它的存在是因为最早的C编译器将以上三种表达式的编译成不同的机器代码,不同的机器代码运行速度不一样。现在,编译器已经基本自动实行代码优化,所以以上三种不同的表达方式编译成的机器代码在实际运行上已基本相同。
这个运算符的一个特点是它既可以被用作prefix前缀,也可以被用作后缀suffix,也就是说它既可以被写在变量标识的前面(++a),也可以被写在后面(a++)。虽然在简单表达式如a++或++a中,这两种写法代表同样的意思,但当递增increase或递减decrease的运算结果被直接用在其它的运算式中时,它们就代表非常不同的意思了:当递增运算符被用作前缀prefix (++a) 时,变量a的值线增加,然后再计算整个表达式的值,因此增加后的值被用在了表达式的计算中;当它被用作后缀suffix (a++)时,变量a的值在表达式计算后才增加,因此a在增加前所存储的值被用在了表达式的计算中。注意以下两个例子的不同:
例 1 | 例 2 |
---|---|
B=3; 的值为 4 | B=3; 的值为 3, B 的值为 4 |
在第一个例子中,B在它的值被赋给A之前增加1。而在第二个例子中B原来的值3被赋给 A然后B的值才加1变为4。
关系运算符Relational operators ( ==, !=, >, <, >=, <= )
我们用关系运算符来比较两个表达式。如ANSI-C++ 标准中指出的,关系预算的结果是一个bool值,根据运算结果的不同,它的值只能是真true或false。
例如我们想通过比较两个表达式来看它们是否相等或一个值是否比另一个的值大。以下为C++的关系运算符:
== | 相等Equal |
!= | 不等Different |
> | 大于Greater than |
< | 小于Less than |
>= | 大于等于Greater or equal than |
<= | 小于等于Less or equal than |
下面你可以看到一些实际的例子:
(7 == 5) | 将返回false. |
(5 > 4) | 将返回true. |
(3 != 2) | 将返回true. |
(6 >= 6) | 将返回true. |
(5 < 5) | 将返回false. |
当然,除了使用数字常量,我们也可以使用任何有效表达式,包括变量。假设有a=2, b=3和c=6,
(a == 5) | 将返回false. |
(a*b >= c) | 将返回true 因为它实际是(2*3 >= 6) |
(b+4 > a*c) | 将返回false因为它实际是(3+4 > 2*6) |
((b=2) == a) | 将返回true. |
注意:运算符= (单个等号)不同于运算符== (双等号)。第一个是赋值运算符(将等号右边的表达式值赋给左边的变量);第二个(==)是一个判断等于的关系运算符,用来判断运算符两边的表达式是否相等。因此在上面例子中最后一个表达式((b=2) == a),我们首先将数值2赋给变量b,然后把它和变量a进行比较。因为变量a中存储的也是数值2,所以整个运算的结果为true。
在ANSI-C++标准出现之前的许多编译器中,就像C语言中,关系运算并不返回值为真true或假false的bool值,而是返回一个整型数值最为结果,它的数值可以为0,代表"false"或一个非0数值(通常为1)来代表"true"。
逻辑运算符Logic operators ( !, &&, || )
运算符 ! 等同于boolean 运算NOT (取非),它只有一个操作数(operand),写在它的右边。它做的唯一工作就是取该操作数的反面值,也就是说如果操作数值为真true,那么运算后值变为假false,如果操作数值为假false,则运算结果为真true。它就好像是说取与操作数相反的值。例如:
!(5 == 5) | 返回false,因为它右边的表达式(5 == 5)为真true. |
!(6 <= 4) | 返回true因为(6 <= 4)为假false. |
!true | 返回假false. |
!false | 返回真true. |
逻辑运算符&&和||是用来计算两个表达式而获得一个结果值。它们分别对应逻辑运算中的与运算AND 和或运算OR。它们的运算结果取决于两个操作数(operand)的关系:
第一个操作数 a | 第二个操作数 b | 结果 a && b | 结果 a || b |
---|---|---|---|
true | true | true | true |
true | false | false | true |
false | true | false | true |
false | false | false | false |
例如 :
( (5 == 5) || (3 > 6)) 返回true ( true || false ).
条件运算符Conditional operator ( ? )
条件运算符计算一个表达式的值并根据表达式的计算结果为真true或假false而返回不同值。它的格式是:
如果条件condition 为真true,整个表达式将返回esult1,否则将返回result2。
7==5 ? 4 : 3 | 返回3,因为7不等于5. |
7==5+2 ? 4 : 3 | 返回4,因为7等于5+2. |
5>3 ? a : b | 返回a,因为5大于3. |
a>b ? a : b | 返回较大值,a 或b. |
// 条件运算符例子 #include <iostream> using namespace std; int main () { int a,b,c; a=2; b=7; c = (a>b) ? a : b; cout << c; return 0; } | 7 |
上面的例子中a的值为2,b的值为7,所以表达式(a>b)运算值为假(false),所以整个表达式(a>b)?a:b要取分号后面的值,也就是b的值7。因此最后输出 c 的值为7。
逗号运算符 ( , )
逗号运算符 (,) 用来分开多个表达式,并只取最右边的表达式的值返回。
例如有以下代码:
这行代码首先将3赋值给变量b,然后将 b+2 赋值给变量 a。所以最后变量 a 的值为5,而变量b的值为 3。
位运算符Bitwise Operators ( &, |, ^, ~, <<, >> )
位运算符以比特位改写变量存储的数值,也就是改写变量值的二进制表示:
op | asm | Description |
---|---|---|
& | AND | 逻辑与 Logic AND |
| | OR | 逻辑或Logic OR |
^ | XOR | 逻辑异或Logical exclusive OR |
~ | NOT | 对1取补(位反转)Complement to one (bit inversion) |
<< | SHL | 左移Shift Left |
>> | SHR | 右移Shift Right |
变量类型转换运算符Explicit type casting operators
变量类型转换运算符可以将一种类型的数据转换为另一种类型的数据。在写C++中有几种方法可以实现这种操作,最常用的一种,也是与C兼容的一种,是在原转换的表达式前面加用括号()括起的新数据类型:
float f = 3.14;
i = (int) f;
以上代码将浮点型数字3.14转换成一个整数值(3)。这里类型转换操作符为(int)。在C++中实现这一操作的另一种方法是使用构造函数constructor 的形式:在要转换的表达式前加变量类型并将表达式括在括号中:
以上两种类型转换的方法在C++中都是合法的。另外ANSI-C++针对面向对象编程(object oriented programming)增加了新的类型转换操作符 (参考Section 5.4, Advanced class type-casting).
sizeof()
这个运算符接受一个输入参数,该参数可以是一个变量类型或一个变量自己,返回该变量类型(variable type) 或对象(object)所占的字节数:
这将会返回1给a,因为char是一个常为1个字节的变量类型。
sizeof返回的值是一个常数,因此它总是在程序执行前就被固定了。
其它运算符
在本教程后面的章节里我们将看到更多的运算符,比如指向指针的运算或面向对象编程特有的运算,等等,我们会在它们各自的章节里进行详细讨论。
运算符的优先度 Precedence of operators
优先级 Level | 操作符 Operator | 说明 Description | 结合方向 Grouping |
---|---|---|---|
1 | :: | 范围 | 从左到右 |
2 | () [] . -> ++ -- dynamic_cast static_cast reinterpret_cast const_cast typeid | 后缀 | 从左到右 |
3 | ++ -- ~ ! sizeof new delete | 一元(前缀) | 从右到左 |
* & | 指针和取地址 | ||
+ - | 一元符号 | ||
4 | (type) | 类型转换 | 从右到左 |
5 | .* ->* | 指向成员的指针 | 从左到右 |
6 | * / % | 乘、除、取模 | 从左到右 |
7 | + - | 加减 | 从左到右 |
8 | << >> | 位移 | 从左到右 |
9 | < > <= >= | 关系操作符 | 从左到右 |
10 | == != | 等于、不等于 | 从左到右 |
11 | & | 按位与运算 | 从左到右 |
12 | ^ | 按位异或运算 | 从左到右 |
13 | | | 按位或运算 | 从左到右 |
14 | && | 逻辑与运算 | 从左到右 |
15 | || | 逻辑或运算 | 从左到右 |
16 | ?: | 条件运算 | 从右到左 |
17 | = *= /= %= += -= >>= <<= &= ^= |= | 赋值运算 | 从右到左 |
18 | , | 逗号 | 从左到右 |
结合方向Grouping定义了当有同优先级的多个运算符在一起时,哪一个必须被首先运算,最右边的还是最左边的
输出Output (cout)
输出流cout与重载(overloaded)运算符<<一起使用:
运算符<<又叫插入运算符(insertion operator) 因为它将后面所跟的数据插入到它前面的数据流中。在以上的例子中,字符串常量Output sentence,数字常量120和变量x先后被插入输出流cout中。注意第一句中字符串常量是被双引号引起来的。每当我们使用字符串常量的时候,必须用引号把字符串引起来,以便将它和变量名明显的区分开来。插入运算符insertion operator (<<)可以在同一语句中被多次使用:
上面这一行语句将会打印 Hello, I am a C++ sentence 到屏幕上。插入运算符(<<) 的重复使用在我们想要打印变量和内容的组合内容或多个变量时有所体现:
如果我们假设变量age的值为24,变量zipcode的值为90064,以上句子的输出将为: Hello, I am 24 years old and my zipcode is 90064
必须注意,除非我们明确指定,cout并不会自动在其输出内容的末尾加换行符,你可以使用\n或endl来指定cout输出换行.
输入Input (cin)
C++中的标准输入是通过在cin数据流上重载运算符extraction (>>) 来实现的。它后面必须跟一个变量以便存储读入的数据。cin 只能在键盘输入回车键(RETURN)后才能处理前面输入的内容。因此即使你只要求输入一个单独的字符,在用户按下回车键(RETURN)之前cin将不会处理用户的输入的字符。
你也可以利用cin 要求用户输入多个数据 :
等同于:
cin >> b;
cin和字符串
我们可以像读取基本类型数据一样,使用cin和>>操作符来读取字符串,但是,cin >> 只能读取一个单词,一旦碰到任何空格,读取操作就会停止。在很多时候这并不是我们想要的操作,比如我们希望用户输入一个英文句子,那么这种方法就无法读取完整的句子,因为一定会遇到空格。要一次读取一整行输入,需要使用C++的函数 getline,相对于是用cin,我们更建议使用getline来读取用户输入。
// 读取字符串例子 #include <iostream> #include <string> using namespace std; int main () { string mystr; cout << "What's your name? "; getline (cin, mystr); cout << "Hello " << mystr << ".\n"; cout << "What is your favorite color? "; getline (cin, mystr); cout << "I like " << mystr << " too!\n"; return 0; }
字符串流 (stringstream)
标准头文件 <sstream> 定义了一个叫做 stringstream的类,使用这个类可以对基于字符串的对象进行像流(stream)一样的操作。这样,我们可以对字符串进行抽取和插入操作,这对将字符串与数值互相转换非常有用。例如,如果我们想将一个字符串转换为一个整数,可以这样写:
string mystr ("1204"); int myint; stringstream(mystr) >> myint;
重复结构 Iteration structures 或循环loops
循环Loops 的目的是重复执行一组语句一定的次数或直到满足某种条件。
while 循环
格式是:
while (表达式expression) 语句statement
它的功能是当expression 的值为真true时重复执行statement。
我们必须考虑到循环必须在某个点结束,因此在语句块之内(loop的statement之内) 我们必须提供一些方法使得条件condition 可以在某个时刻变为假 false,否则循环将无限重复下去。do-while 循环
格式:
do 语句statement while (条件condition);
它的功能与while 循环一抹一样,除了在do-while循环中是先执行statement 然后才检查条件condition ,而不想while循环中先检查条件然后才执行statement。
for 循环
格式是:
for (initialization; condition; increase) statement;
它的主要功能是当条件condition 为真true时重复执行语句statement ,类似while 循环。但除此之外,for 还提供了写初始化语句initialization 和增值语句increase 的地方。因此这种循环结构是特别为执行由计数器控制的循环而设计的。
分支控制和跳转(Bifurcation of control and jumps)
break 语句
通过使用break语句,即使在结束条件没有满足的情况下,我们也可以跳出一个循环。它可以被用来结束一个无限循环(infinite loop),或强迫循环在其自然结束之前结束。例如,我们想要在倒计数自然结束之前强迫它停止(也许因为一个引擎故障):
continue 语句
continue语句使得程序跳过当前循环中剩下的部分而直接进入下一次循环,就好像循环中语句块的结尾已经到了使得循环进入下一次重复。
exit 函数
exit是一个在cstdlib (stdlib.h)库中定义的函数。
exit的目的是一个特定的退出代码来结束程序的运行,它的原型(prototype)是:
void exit (int exit code);
exit code是由操作系统使用或被调用程序使用。通常exit code为0表示程序正常结束,任何其他值表示程序执行过程中出现了错误。
选择结构The selective Structure: switch
switch 语句的语法比较特殊。它的目标是对一个表达式检查多个可能常量值,有些像我们在本节开头学习的把几个if 和else if 语句连接起来的结构。它的形式是:
case constant1:
block of instructions 1
break;
case constant2:
block of instructions 2
break;
.
.
.
default:
default block of instructions
}
它按以下方式执行:
switch 计算表达式expression 的值,并检查它是否与第一个常量constant1相等,如果相等,程序执行常量1后面的语句块block of instructions 1 直到碰到关键字break ,程序跳转到switch 选择结构的结尾处。
如果expression 不等于constant1,程序检查表达式expression 的值是否等于第二个常量constant2, 如果相等,程序将执行常量2后面的语句块block of instructions 2 直到碰到关键字break。
依此类推,直到最后如果表达式expression 的值不等于任何前面的常量(你可以用case语句指明任意数量的常量值来要求检查),程序将执行默认区default: 后面的语句,如果它存在的话。default: 选项是可以省略的。