跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
cplus:第二章运算符与表达式
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第二章 运算符与表达式 ====== 本章将详细介绍C++中的各种运算符和表达式,包括算术运算符、关系运算符、逻辑运算符、位运算符等,以及运算符优先级和结合性的规则。 ===== 2.1 算术运算符 ===== === 2.1.1 基本算术运算符 === C++提供了五种基本算术运算符: | 运算符 | 名称 | 示例 | 结果 | |--------|------|------|------| | + | 加法 | 5 + 3 | 8 | | - | 减法 | 5 - 3 | 2 | | * | 乘法 | 5 * 3 | 15 | | / | 除法 | 5 / 3 | 1(整数除法) | | % | 取模 | 5 % 3 | 2 | <code cpp> #include <iostream> using namespace std; int main() { int a = 17, b = 5; cout << "a + b = " << a + b << endl; // 22 cout << "a - b = " << a - b << endl; // 12 cout << "a * b = " << a * b << endl; // 85 cout << "a / b = " << a / b << endl; // 3(整数除法,截断小数) cout << "a % b = " << a % b << endl; // 2(余数) // 浮点数除法 double x = 17.0, y = 5.0; cout << "x / y = " << x / y << endl; // 3.4 return 0; } </code> === 2.1.2 除法的注意事项 === <code cpp> #include <iostream> using namespace std; int main() { // 整数除法 vs 浮点数除法 cout << 17 / 5 << endl; // 3(整数除法) cout << 17.0 / 5 << endl; // 3.4(浮点数除法) cout << 17 / 5.0 << endl; // 3.4 cout << static_cast<double>(17) / 5 << endl; // 3.4(显式转换) // 除以零(未定义行为) // cout << 5 / 0; // 运行时错误或崩溃 // 取模运算的符号 cout << 17 % 5 << endl; // 2 cout << -17 % 5 << endl; // -2(符号与被除数相同) cout << 17 % -5 << endl; // 2 cout << -17 % -5 << endl; // -2 return 0; } </code> === 2.1.3 自增和自减运算符 === <code cpp> #include <iostream> using namespace std; int main() { int a = 5, b = 5; // 前缀形式:先增减,后使用 cout << ++a << endl; // 6(a先变为6,然后输出) cout << --a << endl; // 5(a先变为5,然后输出) // 后缀形式:先使用,后增减 cout << b++ << endl; // 5(先输出5,然后b变为6) cout << b << endl; // 6 cout << b-- << endl; // 6(先输出6,然后b变为5) cout << b << endl; // 5 // 复杂示例 int x = 3, y = 3; int result1 = ++x + 2; // x=4, result1=6 int result2 = y++ + 2; // result2=5, y=4 // 不要在同一表达式中多次修改同一变量(未定义行为) // int bad = ++x + x++; // 未定义行为! return 0; } </code> === 2.1.4 复合赋值运算符 === <code cpp> #include <iostream> using namespace std; int main() { int a = 10; a += 5; // 等价于 a = a + 5; a = 15 a -= 3; // 等价于 a = a - 3; a = 12 a *= 2; // 等价于 a = a * 2; a = 24 a /= 4; // 等价于 a = a / 4; a = 6 a %= 4; // 等价于 a = a % 4; a = 2 // 位运算的复合赋值 int b = 0b1010; // 10 b &= 0b1100; // b = b & 0b1100; b = 0b1000 (8) b |= 0b0001; // b = b | 0b0001; b = 0b1001 (9) b ^= 0b0010; // b = b ^ 0b0010; b = 0b1011 (11) b <<= 1; // b = b << 1; b = 0b10110 (22) b >>= 2; // b = b >> 2; b = 0b101 (5) return 0; } </code> ===== 2.2 关系运算符 ===== === 2.2.1 关系运算符 === | 运算符 | 名称 | 示例 | 结果(a=5, b=3) | |--------|------|------|-----------------| | == | 等于 | a == b | false | | != | 不等于 | a != b | true | | < | 小于 | a < b | false | | > | 大于 | a > b | true | | <= | 小于等于 | a <= b | false | | >= | 大于等于 | a >= b | true | <code cpp> #include <iostream> using namespace std; int main() { int a = 5, b = 3; cout << "a == b: " << (a == b) << endl; // 0 (false) cout << "a != b: " << (a != b) << endl; // 1 (true) cout << "a < b: " << (a < b) << endl; // 0 cout << "a > b: " << (a > b) << endl; // 1 cout << "a <= b: " << (a <= b) << endl; // 0 cout << "a >= b: " << (a >= b) << endl; // 1 // 用于条件判断 if (a > b) { cout << "a is greater than b" << endl; } // 比较浮点数(注意精度问题) double x = 0.1 + 0.2; double y = 0.3; // 错误的方式 if (x == y) { // 可能为false cout << "Equal" << endl; } // 正确的方式 const double EPSILON = 1e-9; if (fabs(x - y) < EPSILON) { cout << "Approximately equal" << endl; } return 0; } </code> === 2.2.2 关系运算符的连写误区 === <code cpp> #include <iostream> using namespace std; int main() { int x = 5; // 错误:C++不支持数学式的连写比较 // if (1 < x < 10) // 逻辑错误! // 正确的方式 if (1 < x && x < 10) { cout << "x is between 1 and 10" << endl; } // 解释错误写法的问题 // (1 < x < 10) 被解析为 ((1 < x) < 10) // 1 < 5 是 true,转换为 1 // 然后 1 < 10 是 true // 所以即使 x = -100,结果也是 true! return 0; } </code> ===== 2.3 逻辑运算符 ===== === 2.3.1 基本逻辑运算符 === | 运算符 | 名称 | 说明 | |--------|------|------| | && | 逻辑与 | 两边都为真时结果为真 | | || | 逻辑或 | 至少一边为真时结果为真 | | ! | 逻辑非 | 取反 | 真值表: | a | b | a && b | a || b | !a | |---|---|--------|--------|-----| | true | true | true | true | false | | true | false | false | true | false | | false | true | false | true | true | | false | false | false | false | true | <code cpp> #include <iostream> using namespace std; int main() { bool a = true, b = false; cout << "a && b: " << (a && b) << endl; // 0 cout << "a || b: " << (a || b) << endl; // 1 cout << "!a: " << !a << endl; // 0 cout << "!b: " << !b << endl; // 1 // 短路求值 int x = 5; // && 短路:如果左边为假,右边不执行 if (false && (++x > 0)) { // 不会执行 } cout << "x = " << x << endl; // x仍然是5 // || 短路:如果左边为真,右边不执行 if (true || (++x > 0)) { // 会执行这里 } cout << "x = " << x << endl; // x仍然是5 return 0; } </code> === 2.3.2 短路求值的应用 === <code cpp> #include <iostream> using namespace std; int main() { int* ptr = nullptr; int value = 10; // 安全的空指针检查 // 如果 ptr 为空,不会访问 *ptr if (ptr != nullptr && *ptr > 0) { cout << "Value is positive" << endl; } // 另一种写法 ptr = &value; if (ptr && *ptr > 0) { // ptr 转换为 bool 检查是否为空 cout << "Value: " << *ptr << endl; } // 设置默认值 int* configValue = nullptr; int defaultValue = 100; // 如果 configValue 有效则使用,否则使用默认值 int result = (configValue ? *configValue : defaultValue); cout << "Result: " << result << endl; return 0; } </code> ===== 2.4 位运算符 ===== === 2.4.1 位运算符 === | 运算符 | 名称 | 说明 | |--------|------|------| | & | 按位与 | 对应位都为1时结果为1 | | | | 按位或 | 对应位至少一个为1时结果为1 | | ^ | 按位异或 | 对应位不同时结果为1 | | ~ | 按位取反 | 所有位取反 | | << | 左移 | 位向左移动,右侧补0 | | >> | 右移 | 位向右移动 | <code cpp> #include <iostream> #include <bitset> using namespace std; int main() { unsigned int a = 0b1100; // 12 unsigned int b = 0b1010; // 10 cout << "a = " << bitset<4>(a) << " (" << a << ")" << endl; cout << "b = " << bitset<4>(b) << " (" << b << ")" << endl; cout << "a & b = " << bitset<4>(a & b) << " (" << (a & b) << ")" << endl; // 1000 (8) cout << "a | b = " << bitset<4>(a | b) << " (" << (a | b) << ")" << endl; // 1110 (14) cout << "a ^ b = " << bitset<4>(a ^ b) << " (" << (a ^ b) << ")" << endl; // 0110 (6) cout << "~a = " << bitset<4>(~a) << " (" << ~a << ")" << endl; // 取反 cout << "a << 1 = " << bitset<4>(a << 1) << " (" << (a << 1) << ")" << endl; // 11000 (24) cout << "a >> 1 = " << bitset<4>(a >> 1) << " (" << (a >> 1) << ")" << endl; // 0110 (6) return 0; } </code> === 2.4.2 位运算的实际应用 === <code cpp> #include <iostream> using namespace std; // 权限标志位 const int READ = 1 << 0; // 0001 = 1 const int WRITE = 1 << 1; // 0010 = 2 const int EXECUTE = 1 << 2; // 0100 = 4 const int DELETE = 1 << 3; // 1000 = 8 int main() { // 设置权限 int permission = READ | WRITE; // 添加读和写权限 // 检查权限 if (permission & READ) { cout << "Can read" << endl; } if (permission & EXECUTE) { cout << "Can execute" << endl; // 不会输出 } // 添加权限 permission |= EXECUTE; // 添加执行权限 // 移除权限 permission &= ~WRITE; // 移除写权限 // 切换权限 permission ^= READ; // 切换读权限(有则移除,无则添加) // 快速乘除2的幂 int x = 10; cout << "x * 8 = " << (x << 3) << endl; // 80 cout << "x / 4 = " << (x >> 2) << endl; // 2 // 判断奇偶 int num = 15; if (num & 1) { cout << num << " is odd" << endl; } else { cout << num << " is even" << endl; } // 交换两个数(不使用临时变量) int a = 5, b = 3; a = a ^ b; b = a ^ b; a = a ^ b; cout << "a = " << a << ", b = " << b << endl; // a=3, b=5 return 0; } </code> ===== 2.5 条件运算符 ===== === 2.5.1 三元运算符 === <code cpp> #include <iostream> using namespace std; int main() { int a = 10, b = 20; // 基本用法 int max = (a > b) ? a : b; cout << "Max: " << max << endl; // 20 // 嵌套使用(可读性较差,谨慎使用) int score = 85; char grade = (score >= 90) ? 'A' : (score >= 80) ? 'B' : (score >= 70) ? 'C' : (score >= 60) ? 'D' : 'F'; cout << "Grade: " << grade << endl; // B // 类型必须兼容或可转换 auto result = true ? 1 : 2.0; // result是double // 与if-else对比 int x = 10; // 三元运算符版本 int abs1 = (x >= 0) ? x : -x; // if-else版本 int abs2; if (x >= 0) { abs2 = x; } else { abs2 = -x; } return 0; } </code> ===== 2.6 sizeof运算符 ===== <code cpp> #include <iostream> using namespace std; int main() { // 基本类型的大小 cout << "sizeof(char) = " << sizeof(char) << endl; cout << "sizeof(short) = " << sizeof(short) << endl; cout << "sizeof(int) = " << sizeof(int) << endl; cout << "sizeof(long) = " << sizeof(long) << endl; cout << "sizeof(long long) = " << sizeof(long long) << endl; cout << "sizeof(float) = " << sizeof(float) << endl; cout << "sizeof(double) = " << sizeof(double) << endl; cout << "sizeof(bool) = " << sizeof(bool) << endl; // 变量的大小 int arr[10]; cout << "sizeof(arr) = " << sizeof(arr) << endl; // 40(10 * 4) cout << "sizeof(arr[0]) = " << sizeof(arr[0]) << endl; // 4 // 计算数组元素个数 int n = sizeof(arr) / sizeof(arr[0]); cout << "Array elements: " << n << endl; // C++11: sizeof... 获取变参模板参数个数 return 0; } </code> ===== 2.7 类型转换运算符 ===== === 2.7.1 C++类型转换 === <code cpp> #include <iostream> using namespace std; class Base { public: virtual ~Base() {} }; class Derived : public Base { public: void derivedOnly() {} }; int main() { double d = 3.14; // 1. static_cast - 静态类型转换 int i = static_cast<int>(d); cout << "i = " << i << endl; // 用于类层次中的上行转换 Derived derivedObj; Base* basePtr = static_cast<Base*>(&derivedObj); // 2. dynamic_cast - 动态类型转换(用于多态) Base* b = new Derived(); Derived* d2 = dynamic_cast<Derived*>(b); if (d2) { d2->derivedOnly(); } // 3. const_cast - 添加或移除const const int x = 10; int* p = const_cast<int*>(&x); // *p = 20; // 未定义行为!不要修改const对象 int y = 10; const int* cp = &y; int* qp = const_cast<int*>(cp); *qp = 20; // 合法,y不是const // 4. reinterpret_cast - 底层重新解释 int num = 65; char* c = reinterpret_cast<char*>(&num); // C++11新增 // 5. static_pointer_cast, dynamic_pointer_cast, const_pointer_cast - 用于智能指针 delete b; return 0; } </code> ===== 2.8 运算符优先级 ===== === 2.8.1 优先级表 === | 优先级 | 运算符 | 说明 | 结合性 | |--------|--------|------|--------| | 1 | :: | 作用域解析 | 左到右 | | 2 | () [] -> . ++ -- | 后缀 | 左到右 | | 3 | ++ -- + - ! ~ * & sizeof | 前缀 | 右到左 | | 4 | .* ->* | 成员指针 | 左到右 | | 5 | * / % | 乘除模 | 左到右 | | 6 | + - | 加减 | 左到右 | | 7 | << >> | 位移 | 左到右 | | 8 | < <= > >= | 关系 | 左到右 | | 9 | == != | 相等 | 左到右 | | 10 | & | 按位与 | 左到右 | | 11 | ^ | 按位异或 | 左到右 | | 12 | | | 按位或 | 左到右 | | 13 | && | 逻辑与 | 左到右 | | 14 | || | 逻辑或 | 左到右 | | 15 | ?: | 条件 | 右到左 | | 16 | = += -= 等 | 赋值 | 右到左 | | 17 | , | 逗号 | 左到右 | === 2.8.2 优先级示例 === <code cpp> #include <iostream> using namespace std; int main() { int a = 5, b = 3, c = 2; // 乘除优先于加减 int result1 = a + b * c; // 5 + 6 = 11,不是 16 // 赋值优先级很低 int x, y; x = y = 10; // 先 y = 10,然后 x = y // 关系运算符优先于逻辑运算符 bool result2 = a > b && b > c; // (a > b) && (b > c) // 位运算符优先级容易出错 int flags = 0b1010; if (flags & 0b1000 == 0b1000) { // 错误!相当于 flags & (0b1000 == 0b1000) // 即 flags & 1 } if ((flags & 0b1000) == 0b1000) { // 正确 } // 条件运算符 int max = a > b ? a : b; // 逗号运算符 int i = (1, 2, 3); // i = 3 // 建议使用括号明确优先级 int complex = ((a + b) * c - a) / b; return 0; } </code> ===== 2.9 表达式求值 ===== === 2.9.1 左值和右值 === <code cpp> #include <iostream> using namespace std; int global = 10; int getValue() { return 10; // 返回临时值(右值) } int& getGlobal() { return global; // 返回引用(左值) } int main() { int x = 10; int y = 20; // 左值(lvalue):有身份,可取地址 x = 15; // x是左值 &x; // 可以取地址 // 右值(rvalue):临时值,不可取地址 // 10 = x; // 错误!10是右值 // &10; // 错误! // 左值引用 int& ref = x; // 正确,绑定到左值 // int& ref2 = 10; // 错误,不能绑定到右值 // 右值引用(C++11) int&& rref = 10; // 正确,绑定到右值 int&& rref2 = x + y; // 正确 // 应用场景 getGlobal() = 20; // 正确,返回左值 // getValue() = 20; // 错误,返回右值 return 0; } </code> === 2.9.2 求值顺序 === <code cpp> #include <iostream> using namespace std; int f1() { cout << "f1" << endl; return 1; } int f2() { cout << "f2" << endl; return 2; } int f3() { cout << "f3" << endl; return 3; } int main() { // 函数参数的求值顺序未指定 // 可能是 f1, f2, f3 或任何顺序 cout << f1() + f2() + f3() << endl; // 以下代码有未定义行为 int i = 0; // int x = ++i + i++; // 未定义行为! // C++17起,某些运算符的求值顺序确定: // e1.e2, e1->e2, e1[e2], e1<<e2, e1>>e2 // 安全写法 i = 0; int a = ++i; int b = i++; int c = a + b; return 0; } </code> ===== 2.10 逗号运算符 ===== <code cpp> #include <iostream> using namespace std; int main() { int a, b, c; // 逗号表达式:从左到右求值,结果为最后一个表达式的值 c = (a = 1, b = 2, a + b); // c = 3 cout << "c = " << c << endl; // 在for循环中使用 for (int i = 0, j = 10; i < j; i++, j--) { cout << "i=" << i << ", j=" << j << endl; } // 注意:函数参数中的逗号是分隔符,不是运算符 // func(a, b); // 两个参数 // func((a, b)); // 一个参数,值为b return 0; } </code> ===== 2.11 本章小结 ===== 本章我们学习了: * 算术运算符及其特殊注意事项(整数除法、取模) * 关系运算符和常见错误 * 逻辑运算符及其短路求值特性 * 位运算符及其在标志位、优化计算中的应用 * 条件运算符(三元运算符)的用法 * sizeof运算符获取类型和对象大小 * C++四种类型转换运算符 * 运算符优先级和结合性 * 左值与右值的概念 * 表达式求值顺序的重要性 理解运算符的行为和优先级是写出正确、高效C++代码的基础。 ===== 练习题 ===== **基础练习:** 1. 编写程序实现两个数的交换,分别使用: - 临时变量 - 算术运算 - 异或运算 2. 解释以下表达式的结果: <code cpp> int a = 5, b = 3; int c = a++ + ++b; int d = (a > b) ? a++ : ++b; </code> 3. 使用位运算实现以下功能: - 判断一个数是否是2的幂 - 计算一个数的二进制中1的个数 - 交换两个数的特定位 4. 编写程序使用标志位管理文件权限(读、写、执行) **进阶练习:** 5. 实现一个函数,不使用+运算符实现两个整数相加(使用位运算) 6. 分析以下代码的问题并修正: <code cpp> double x = 0.1, y = 0.2; if (x + y == 0.3) { cout << "Equal" << endl; } </code> 7. 解释short-circuit evaluation在以下代码中的作用: <code cpp> if (ptr != nullptr && ptr->value > 0) { } if (index >= 0 && index < size && array[index] == target) { } </code> **思考题:** 8. 为什么C++的运算符优先级设计成这样?分析几个设计决策。 9. 研究volatile关键字对运算符行为的影响。 10. C++11引入的右值引用如何改变表达式的分类? ===== 参考答案 ===== **练习1参考(异或交换):** <code cpp> void swap(int& a, int& b) { if (&a != &b) { // 必须检查是否同一地址 a ^= b; b ^= a; a ^= b; } } </code> **练习3参考(判断2的幂):** <code cpp> bool isPowerOfTwo(int n) { return n > 0 && (n & (n - 1)) == 0; } </code> **练习5参考(位运算加法):** <code cpp> int add(int a, int b) { while (b != 0) { int carry = a & b; // 计算进位 a = a ^ b; // 无进位加法 b = carry << 1; // 进位左移 } return a; } </code> ===== 下一章 ===== 继续学习:[[第三章_控制结构|第三章 控制结构]]
cplus/第二章运算符与表达式.txt
· 最后更改:
2026/02/03 19:45
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部