1.算数运算符:
+(加法运算)
-(减法运算)
*(乘法运算)
/(除法运算)
%(求余运算)
注意:在进行整数除法时,得到结果仍然是整数,例如5/2得到的结果是2,而不是2.5
2.关系运算符:
==(等于运算符):判断两个数是否相等
!=:(不等于运算符)
>:(大于运算符)
<:(小于运算符)
>=:(大于等于运算符)
<=:(小于等于运算符)
注意:关系运算符的返回值为bool类型,为true或false
3.逻辑运算符:
&&:(逻辑与运算符) 当且仅当两个操作数都为真时,结果为真
||:(逻辑或运算符) 只要两个操作数中有一个为真,结果就为真
!:(逻辑非运算符) 用于对一个操作数取反。如果操作数为真,则结果为假;如果操作数为假,则结果为真。
注意:逻辑运算符的返回值同样也是bool类型,取值为true或false
4.赋值运算符:
=:(简单赋值运算符) 用于将一个值赋给一个变量
复合运算符:+=、-=、*=、/=、%=
以+=为例,a+=3等价于a=a+3,其他复合运算符也是如此。
5.位运算符:
&(按位与运算符): 对两个二进制数的每一位进行逻辑与操作。只有当两个相应位都为 1 时,结果位才为 1,否则为 0。
int ans = 3 & 5;
cout << ans;//ans的结果为1
例如3与5做按位与运算,3的二进制为0011,5的二进制为0101,进行与运算之后得到的结果为0001,转换成10进制就是1.
|(按位或运算符):对两个二进制数的每一位进行逻辑或操作。只要两个相应位中有一个为 1,结果位就为 1;只有当两个位都为 0 时,结果位才为 0。
int ans = 3 | 5;
cout << ans;//ans的结果为7
还是3与5进行按位或运算,0011与0101进行或运算得到的结果为0111,转换成十进制的结果就是7。
^(按位异或运算符):对两个二进制数的每一位进行逻辑异或操作。当两个相应位不同(一个为 0,另一个为 1)时,结果位为 1;当两个位相同(都为 0 或都为 1)时,结果位为 0。
int ans = 3 ^ 5;
cout << ans;//ans的结果为6
0011与0101进行异或运算得到的结果为0110,转化成十进制的结果为6
<<(左移运算符):是将一个二进制数的所有位向左移动指定的位数。左移后,右边空出的位用 0 填充。
>>(右移运算符):将一个二进制数的所有位向右移动指定的位数。
int a = (3 << 2);
int b = (6 >> 1);
cout << a << endl;//结果为12
cout << b << endl;//结果为3
左移运输符和右移运算符相当于将一个数扩大(缩小)2的n次方倍。例如a左移两位,相当于扩大了4倍,得到的结果就是12,b右移1位,相当于乘1/2,得到的结果就是3。
6.三目运算符:
?= :根据条件选择两个值中的一个。
格式:条件表达式 ? 表达式1 :表达式2
运算规则:先计算条件表达式的值,如果 “条件表达式” 的值为真,那么整个三目运算的结果就是 “表达式 1” 的值;如果 “条件表达式” 的值为假(即值为 0),那么整个三目运算的结果就是 “表达式 2” 的值
int a = 5;
int b = 3;
int c = (a > b) ? a : b;
cout << c;
输出c的值为5,因为a>b的结果为真,那么就将a的值赋值给c。
7.取地址运算符:
&(取地址) 返回一个量的地址
#include<iostream>
using namespace std;
int main() {
int a = 5;
string s = "hello word";
cout << &a << endl;
cout << &s << endl;
return 0;
}
返回的结果为一个用16进制表示的一个地址,如
8.间接寻址运算符:
* 通过地址访问变量的值
#include<iostream>
using namespace std;
int main() {
int* p = new int(10);
cout << *p << endl;
return 0;
}
通过*p可以到到int*类型的一个在堆区内存上的指针变量p的值,结果为10。
扩展1:按位与运算的应用(判断奇偶数)
为什么用按位与运算判断奇偶数?
效率高,这是因为从计算机执行的角度来看,按位与运算在底层硬件层面是非常高效的操作。计算机的处理器能够快速地执行位运算,相比其他判断奇偶数的方法(如使用取余运算 n % 2),按位与运算通常可以在更少的指令周期内完成。
原理?
在二进制表示中,偶数的最低位(最右边的位)一定是 0,奇数的最低位一定是 1。这是因为二进制数的位权是 2 的幂次方,最低位的位权是 2 ^ 0 = 1。当一个数能被 2 整除(即偶数)时,它的二进制表示中就不会有单独的 1 存在于最低位;而奇数除以 2 会余 1,这个余数 1 就体现在二进制的最低位上。
按位与运算( & )是对两个二进制数的每一位进行逻辑与操作。当用一个数与 1 进行按位与运算时,因为 1 的二进制表示是 00000001(假设是 8 位整数,这里只是举例,实际对于任何位宽的整数原理相同),只有最低位是 1,其他位都是 0。
所以,对于任何整数 n,当 n & 1 进行运算时,实际上是将 n 的最低位与 1 进行与操作。如果 n 是偶数,其最低位是 0,0 & 1 = 0;如果 n 是奇数,其最低位是 1,1 & 1 = 1。
#include<iostream>
using namespace std;
int main() {
int a = 88;
if ((a & 1) == 1) {
cout << "a是奇数" << endl;
}
else {
cout << "a是偶数" << endl;
}
return 0;
}
运行的结果为a是偶数。
总结:在判断一个数是奇数还是偶数时,使用与运算会使效率更加高效。
扩展2:三目运算符与if...else的运行效率?
三目运算符效率通常更高的情况:
编译层面分析:在编译器处理代码时,三目运算符(条件表达式 ? 表达式1 : 表达式2)是一个表达式,编译器在优化过程中可能会将其转换为简单的跳转指令或者条件传送指令。例如,在一些简单的赋值场景中,如int result = (condition) ? value1 : value2; ,编译器能够直接根据condition的值生成高效的机器码,避免复杂的分支预测开销。
假设我们有一个简单的程序,需要根据一个条件来返回两个整数中的较大值,代码如下:
int maxValue(int a, int b) {
return (a > b) ? a : b;
}
对于这种简单的比较和选择操作,编译器可以直接生成比较指令和条件移动指令,将最终结果存储到返回值的寄存器中。相比之下,如果使用if - else结构:
int maxValue(int a, int b) {
if (a > b) {
return a;
}
else {
return b;
}
}
处理器需要执行分支预测来判断是否进入if分支。如果分支预测错误,会导致处理器流水线清空,重新加载指令,从而带来性能开销。在这种简单的场景下,三目运算符的执行效率可能更高。
if....else...效率通常更高的情况:
当条件判断后的执行语句包含复杂的逻辑或者有副作用(如函数调用、修改全局变量等)时,if - else结构更加清晰。例如:
void processData(int data) {
if (data > 10) {
// 可能有复杂的函数调用,修改全局变量等操作
complexFunction1();
globalVariable++;
}
else {
complexFunction2();
anotherGlobalVariable--;
}
}
在这种情况下,使用三目运算符会使代码难以阅读和维护。而且,从效率角度讲,由于涉及复杂的操作,很难直接比较三目运算符和if - else的效率差异,并且在复杂操作下,分支预测的开销可能不是性能的主要影响因素。