
目录1.运算符2.表达式3.运算符的分类3.1 算术运算符(自增运算符)– – (自减运算符)3.2 关系运算符3.3 逻辑运算符C语言逻辑运算符是 惰性运算3.4 位运算符1.~ 按位取反2. 按位与3. | 按位或4. ^ 按位异或有两个变量 a,b 要交换a和b的值 不适用其他临时变量5. 按位左移6. 按位右移7.掩码(mask)8.总结3.5 赋值运算符赋值表达式的值就是赋值完之后 左边那个操作数的值3.6 条件运算符? : 三目运算符3.7 逗号运算符3.8 指针运算符3.9 求字节运算符3.10 分量运算符3.11 下标运算符3.12 强制类型转换4.运算符的优先级和结合性1.运算符什么是运算符运算符是用来表示某种运算(操作)的符号如 - * / % 等根据运算符需要带几个操作数(运算符) 分为 单目运算符该运算符只需要一个操作数 如 - - (取地址符) 等 双目运算符该运算符需要两个操作数 如 - * / % 等 三目运算符该运算符需要三个操作数 如 **? :**结合性决定先算哪个操作数的问题从左至右结合 从右至左结合举个例子在C语言中 已知 的结合性 从左至右a b 和 b a 在C语言中含义不一样的运算符的优先级 在含有多个运算符的表达式中 决定先算哪个运算符 后算哪个运算符 如 a b*c单目运算符 算术运算符 关系运算符 逻辑运算符 赋值运算符 逗号运算符2.表达式什么是表达式 表达某个意思的式子 C语言中的表达式一般来说是用 运算符连接操作数的式子 如: 3 5表达式的值 是一个表达式 就一定会有一个值 这个值就是表达式的值 表达式最终需要表达某个意思 某个意思就是表达式的值 3.运算符的分类3.运算符的分类3.1 算术运算符进行算术运算的运算符 -- 单目运算符* / % 双目运算符 - 双目运算符 - * / 只需要操作数是一个数(整数可以 浮点数可以)% 取余 要求两个操作数必须是 整数如3 43.5 4.73.5 * 63.3 / 25 % 33 % 3.3 error4 / 2 25 / 2 25 / 3 15 / 2.0 2.5(double)(3/2) 1.0(double)3 / 2 1.5(自增运算符)自增(1) 运算符 单目运算符 要求操作必须为一个左值(lvalue)在C语言中 只有变量才具备左值前置: 在前面 x后置: 在后面 x– – (自减运算符)自减(1) 运算符 单目运算符 要求操作必须为一个左值(lvalue)在C语言中 只有变量才具备左值前置- -: - - 在前面 - - x后置- -: - -在后面 x- -表达式的值 做完表达式之后 i 的值i i i i 1i i1 i i 1i-- i i i - 1--i i-1 i i - 1例子 int i 5; int j 6; int a; a (i) (ij);//a17 或 a (ij) (i);//a163.2 关系运算符用来判断两个东西的 关系的运算符 关系数值大小关系 比 数值大小双目运算符 结合性 从左至右 (等于) ! (不等于)关系表达式 用关系运算符连接起来的表达式 如 a b关系表达式的值 关系成立 关系不成立 0如5 3 表达式的值是 15 7 表达式的值是 05 5 表达式的值是 15 4 3 表达式的值为 0结合型 从左至右 (54) 3 1 3 05 4 3 是一个合法的表达式 是拿 5 4 的值 和 3 进行比较在C语言中 5 4 3 这个表达式和数学上 5 4 3 的含义是不一样的(1) C语言中 5 4 3 (5 4) 3(2) 数学上 5 4 3 是 5 4 并且 4 33.3 逻辑运算符! 逻辑非 单目运算符 取反 逻辑与 双目运算符 并且 从左至右|| 逻辑或 双目运算符 或者 从左至右逻辑表达式用逻辑运算符 (! ||) 连接起来的式子 称为 逻辑表达式逻辑表达式的值 真1 假0但是非0 也是逻辑真a b ab a||b真 真 真 真真 假 假 真假 真 假 真假 假 假 假例子 int a 4; int b 5; a b 1 a || b 1 !a b 假 真 0注意优先级5 3 8 4 - !05 3 8 4 - 15 3 8 31 0 真 假 假 所以表达式的值 0练习1. 分析如下程序的输出结果 #include stdio.h int main() { int a,b,c,d,m,n; a 1; b 2; c 3; d 4; m 1; n 1; (m a b) (n c d); printf(%d %d %d %d %d %d\n,a,b,c,d,m,n);//1 2 3 4 0 1 }C语言逻辑运算符是惰性运算a b c只有当a为真 才需要判断b的值只有当 a b 都为真 才需要判断 c的值a || b || c只要a的值为真 就不需要判断b和c的值只有 a 和 b都为假 才需要判断 c 的值总之 如果实现知道了表达式的值啦 那么后面的运算符或表达式就不执行了练习2. 分析如下程序的输出结果 注 的优先级比 || 高 提示考虑运算符的结合性(从左至右) //优先级不等于求值顺序 优先级只是为了确保正确的分组 求值一定是从左往右 //(group) || (c c - 1) int a 0,b 1,c 1; int d a (b b - 1) || (c c - 1); printf(%d %d %d %d\n,a,b,c,d);//0 1 0 0 /* ( a (b b - 1) ) || (c c - 1) x || y 0 || 0 */ //a || (group) int a 1,b 1,c 1; int d a || (b b - 1) (c c - 1); printf(%d %d %d %d\n,a,b,c,d);//1 1 1 1 /* a || ( (b b - 1) (c c - 1) ) x || y x为1 所以y式子 不执行 */ int a 0,b 1,c 1; int d a || (b b - 1) (c c - 1); printf(%d %d %d %d\n,a,b,c,d);//0 0 1 0 /* a || ( (b b - 1) (c c - 1) ) x || y x为0 所以y的值会影响整个式子的值 当y为0 整个式子为0 当y为1 整个式子为1 所以 y需要执行 0 || 0 */3.4 位运算符位运算符 是 按bit位展开来进行的运算 意思就是说 操作数会展开为 bit位 然后再进行运算位运算符要求 操作数必须为整数~ 按位取反 按位与| 按位或^ 按位异或 按位左移 按位右移除了 ~按位取反) 是单目运算符之外 其他所有的都是双目运算符 结合性 从左至右1.~ 按位取反1 - 0 0 - 1 !3 逻辑非 0 ~3 (假设 int 占 32bits) 00000000 00000000 00000000 0000 0011 11111111 11111111 11111111 1111 1100 -- ~3NOTE 按位取反 ~ 和 逻辑非 都是单目运算符!x 对于x没有要求~x 要求x 是整数练习1.分析如下程序的输出结果 #include stdio.h int main() { int a ~(-3); printf(%d\n,a);// 2 printf(%u\n,a);// 2 /* |-3|的原码: 00000000 00000000 00000000 0000 0011 11111111 11111111 11111111 1111 1100 取反 补码: 11111111 11111111 11111111 1111 1101 1 -- -3在计算机中的存放形式 ∴ ~(-3) 00000000 00000000 00000000 0000 0010 */ int b !(-3); printf(%d\n,b);// 0 printf(%u\n,b);// 0 }2. 按位与a b 双目运算符 结合性:从左至右aba b111100010000例子假设int 占 32bits3 5 100000000 00000000 00000000 0000 0011 00000000 00000000 00000000 0000 010100000000 00000000 00000000 0000 00013 7 300000000 00000000 00000000 0000 0011 00000000 00000000 00000000 0000 011100000000 00000000 00000000 0000 0011练习1.假设有一个整型变量a 我要把a的bit5 变为0 其他bit位保持不变 该如何操作a a 0xFFFFFFDF;或a a ~(15) ;结论一个bit位 与 0 进行 按位与 操作 结果为0一个bit为 与 1 进行 按位与 操作 结果 保留原值3. | 按位或a | b 双目运算符 结合性 从左往右aba|b111101011000例子假设int占 32bits3 | 5 700000000 00000000 00000000 0000 0011| 00000000 00000000 00000000 0000 010100000000 00000000 00000000 0000 01113 | 7 700000000 00000000 00000000 0000 0011| 00000000 00000000 00000000 0000 011100000000 00000000 00000000 0000 0111练习1.假设有一个整型变量a 我要把a的bit5 置1 其他bit位保存不变 该如何操作a a | 0x00000020;或a a | (15);结论一个bit位 与 1进行 按位或|操作 结果为1一个bit为 与 0进行 按位或|操作 结果 保留原值4. ^ 按位异或异或求异 不同为1 相同为0aba^b110101011000例子假设int占32bits2^32 3400000000 00000000 00000000 0000 0010^ 00000000 00000000 00000000 0010 000000000000 00000000 00000000 0010 00103 ^ 7 400000000 00000000 00000000 0000 0011^ 00000000 00000000 00000000 0000 011100000000 00000000 00000000 0000 0100练习1.假设有一个整型变量a 我要把a的bit5 保持不变 其他位取反 该如何操作a a ^ 0xFFFFFFDF;或a a ^ ~(15);结论一个bit位 与0进行 按位异或操作 结果保留原值一个bit位 与1进行 按位异或操作 结果 取反有两个变量 a,b 要交换a和b的值 不使用其他临时变量 异或可以实现a a ^ b;b a ^ b;a a ^ b;证明:a b a a ^ b b a ^ b a a ^ b0 0 a0 b0 a0 b0 a0 b00 1 a1 b1 a1 b0 a1 b01 0 a1 b0 a1 b1 a0 b11 1 a0 b1 a0 b1 a1 b15. 按位左移a n 双目运算符 结合性 从左至右 把a按bit位 整体左移n位高位左移后 直接丢弃 低位空出来的n位 直接补0如果丢弃的高位都是0的话 那么左移n位 就表示 乘以 2的n次方1 4 含义 • 1 是int 类型字面量二进制00000001以常见 32 位 int 为例 • 左移运算符整体左移 4 位低位补 0 1 → 二进制 00000001 1 4 → 二进制 00010000十进制 16练习1.构造一个整数(32bits) bit7 和 bit5 为 1 其他bit位 为0 该如何构造(1 5) | (1 7)6. 按位右移x n 双目运算符 结合性 从左至右 把a按bit位整体 右移 n位低位右移 直接丢弃 高位补什么对于无符号数 高位补0对于有符号数 高位补 符号位练习分析如下程序的输出结果 #include stdio.h int main() { int a -1; a a 31; printf(%d\n,a);// -1 printf(%u\n,a);// 2^32 -1 unsigned int b -1; b b 31; printf(%d\n,b);//1 printf(%u\n,b);//1 }7.掩码(mask)掩码是一种位模式掩码中为1的bit位 表示我们要选取的bit位集合通俗来讲 就是表示你对哪些bit位感兴趣如我们要选取 bit0 和 bit1 那么 掩码 0x300000000 00000000 00000000 0000 0011如果 mask 0xFF 表示我要选取 低八位00000000 00000000 00000000 1111 1111例子1.假设有一个整型变量 x 0x345678AB 我要选取x的低八位低八位的掩码 0xFFx ( (18)-1 ) 0xAB2.假设有一个整型变量x 我想要选取x中的 bit5开始的4个bit位(往高位走) 该如何操作 mask: 00000000 00000000 0000 0001 1110 0000 mask: ( (14) - 1) 5 注 ( (14) -1 ) : 0xF x mask xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 00000000 00000000 00000001 11100000 00000000 00000000 0000000x xxx00000 -- ( x ( 0xF 5 ) ) ( x ( 0xF 5 ) ) 58.总结清0 : 0置1 : |1取反 : ^13.5 赋值运算符a b 双目运算符 结合性 从右往左 把表达式b的值 赋值给 a赋值运算符的优先级 排倒数第二 倒数第一是逗号运算符a b把表达式b的值 赋值给a把这个值b写入到a的地址中去a需要具备一个可写的地址(左值) 变量赋值符号左边的操作数必须为可写的地址例子5 5 //error 5 5 //ok 2 3 5;//2 3 表达式 不具备左值 int x 2,y 3; x y 5;//error x y也是表达式 x 5;//ok x 6; /* 4-赋值运算符.c: In function ‘main’: // 赋值操作的左边需要是一个左值 4-赋值运算符.c:6:9: error: lvalue required as left operand of assignment 6 | x 6; | ^ */赋值表达式由赋值运算符连接操作数的式子 称为 赋值表达式赋值表达式的值就是赋值完之后 左边那个操作数的值y x 3;y (x 3); //x 3 是一个赋值表达式这个表达式的值 就是 x的值把赋值表达式 x 3 的值 赋值给 y复合的赋值运算符赋值运算符可以和算术运算符、位运算符组成复合的赋值运算符 - * / % | ^a b;// a a b;a 2;// a a 2;3.6 条件运算符? : 三目运算符expression ? a : b先判断 expression 的值 如果它的值为真(非0) 则整个表达式的值为 a如果它的值为假(0) 则整个表达式的值为 bif(a b) { x 250; } else { x 360; } x (ab?250:360); 或 ab?(x 250):(x 360);3.7 逗号运算符a,b 双目运算符 结合性 从左至右 优先级最低先计算表达式a的值 然后再算 表达式b的值整个逗号表达式的值就是最右边那个表达式的值表达式1表达式2例子a (3,2) //a的值为 2这是把表达式 (3,2) 的值 赋值为 aa 3,a 2a 3,a 2,a 4 (a 3,a 2),a 4逗号表达式的形式可以是下面这样的表达式1表达式2表达式3 …. , 表达式n求值顺序先算表达式1 再算表达式2 再算表达式3 …. 最后算表达式n的值整个逗号表达式的值 就是最右边那个表达式的值分析如下程序的结果int main() { int a,b,c,d; int e (a 5,b 6,c 7,d 8); printf(%d %d %d %d %d\n,a,b,c,d,e);//5 6 7 8 8 }3.8 指针运算符* 指向运算符 取地址运算符3.9 求字节运算符sizeof()int a[10];//数组名为a 数组元素个数10个 a[0] ~ a[9] 数组元素的类型 intsizeof(a[0]): 4 bytessizeof(a) : 40 bytes3.10 分量运算符.-3.11 下标运算符[]如取数组的元素a[0]a[1]....3.12 强制类型转换(类型)表达式(int)3.5(int)(3.24.9) 8(int)3.2 4.9 7.94.运算符的优先级和结合性运算符结合性() [] - .从左至右! ~ -- (正号) -(负号) *(指向) (取地址符) sizeof从右至左*(乘) /(除) %从左至右(加) -(减)从左至右 从左至右 从左至右 !从左至右 按位与从左至右^ 按位异或从左至右| 按位或从左至右从左至右||从左至右?:从右至左 - * / % 从右至左^ | 从右至左,从左至右