快速学C语言——第 4 章:运算符与表达式
第 4 章运算符与表达式 在编程中我们经常需要对数据进行各种计算和比较就像在数学中一样。C 语言提供了一系列运算符让我们能够对变量和值进行赋值、计算、比较、逻辑判断等操作。将变量、常量和运算符按照语法规则组合在一起就形成了表达式。表达式会产生一个具体的值是构建程序逻辑如条件判断、循环执行、数据计算的基础组成部分。4.1 算术运算符算术运算符用于执行基本的数学运算包括加、减、乘、除、取模求余数适用于数值类型整型、浮点型数据。运算符描述示例结果加法5 38-减法10 - 46*乘法6 * 742/除法15 / 43 (整数除法)%取模 (求余数)15 % 43 关键注意事项 1、整数除法两个整型数据相除时结果会自动舍弃小数部分仅保留整数而非四舍五入。 2、浮点数除法若至少有一个操作数是浮点型float/double则结果为浮点型保留小数部分。 3、取模运算仅适用于整型数据用于计算除法后的余数结果的正负号与被除数一致如10 % 3 1-10 % 3 -1。示例#includestdio.hintmain(){inta15,b4;floatc15.0f;// 浮点型操作数。intd-15;printf(15 4 %d\n,ab);// 输出19整数加法。printf(15 - 4 %d\n,a-b);// 输出11整数减法。printf(15 * 4 %d\n,a*b);// 输出60整数乘法。printf(15 / 4 %d\n,a/b);// 输出3整数除法舍弃小数。printf(15.0f / 4 %.2f\n,c/b);// 输出3.75浮点数除法。printf(15 %% 4 %d\n,a%b);// 输出3取模正数余数。printf(-15 %% 4 %d\n,d%b);// 输出-3取模余数与被除数同号。return0;}4.2 赋值运算符 赋值运算符用于将右侧的值或表达式结果赋给左侧的变量最基础的是C 语言还提供了复合赋值运算符结合算术 / 位运算的简化写法让代码更简洁。运算符描述示例等价于简单赋值x 5x 5加后赋值x 3x x 3-减后赋值x - 2x x - 2*乘后赋值x * 4x x * 4/除后赋值x / 2x x / 2%取模后赋值x % 3x x % 3 关键注意事项 1、赋值运算符的左侧必须是 “可修改的变量”如a 5合法5 a非法。 2、复合赋值运算符会先执行运算再赋值优先级低于算术运算符。 3、赋值表达式本身也有值值为 “赋值后变量的结果”如a b 5等价于b 5; a 5右结合。示例#includestdio.hintmain(){intx10;x5;// 等价于 x x 5 → x 15。printf(x 5 后x %d\n,x);// 输出15。x*2;// 等价于 x x * 2 → x 30。printf(x * 2 后x %d\n,x);// 输出30。x%7;// 等价于 x x % 7 → 30 ÷ 7 4余2 → x 2。printf(x %% 7 后x %d\n,x);// 输出2。// 赋值表达式的右结合性。inta,b;ab8;// 先执行 b 8再执行 a b。printf(a %d, b %d\n,a,b);// 输出a 8, b 8。return0;}4.3 关系运算符 关系运算符用于比较两个值的大小或相等关系结果是逻辑值 ——1 表示 “真”条件成立0 表示 “假”条件不成立。关系运算的结果常用于条件判断如 if 语句、循环条件。运算符描述示例结果等于5 30 (假)!不等于5 ! 31 (真)大于5 31 (真)小于5 30 (假)大于等于5 51 (真)小于等于5 30 (假) 关键注意事项 1、区分相等判断和赋值这是最常见的编程错误之一如if (a 5)是判断if (a 5)是赋值永远为真。 2、浮点数比较由于精度问题不建议直接用比较浮点数如3.14 3.1400000001可能为假应判断两者差值的绝对值是否小于极小值如fabs(a - b) 1e-6。示例#includestdio.h#includemath.h// 用于fabs函数浮点数绝对值。intmain(){inta10,b20;floatpi13.14f,pi23.1400001f;printf(%d %d 的结果是%d\n,a,b,ab);// 输出0假。printf(%d ! %d 的结果是%d\n,a,b,a!b);// 输出1真。printf(%d %d 的结果是%d\n,a,b,ab);// 输出0假。printf(%d %d 的结果是%d\n,a,b,ab);// 输出1真。// 浮点数比较的正确方式。if(fabs(pi1-pi2)1e-6){// 差值小于10的-6次方视为相等。printf(pi1 和 pi2 相等\n);}else{printf(pi1 和 pi2 不相等\n);}return0;}4.4 逻辑运算符 逻辑运算符用于组合多个关系表达式或逻辑值形成更复杂的条件判断结果同样是 1真或 0假。C 语言支持 “短路求值”能提高运算效率。运算符描述示例结果短路求值规则逻辑与 (AND)(5 3) (5 10)1 (真)左侧为假则右侧不执行||逻辑或 (OR)(5 3) || (5 2)1 (真)左侧为真则右侧不执行!逻辑非 (NOT)!(5 3)0 (假)无单目运算符 关键注意事项 1、逻辑与所有条件都为真结果才为真只要有一个为假结果为假。 2、逻辑或||只要有一个条件为真结果就为真所有条件都为假结果才为假。 3、逻辑非!将真变假、假变真如!0 1!5 0——C 语言中 “非 0 值都视为真”。 4、短路求值逻辑与左侧为假时右侧表达式不执行逻辑或左侧为真时右侧表达式不执行避免无效计算或副作用。示例#includestdio.hintmain(){intage20;inthas_license1;// 1表示真有驾照0表示假无驾照。intx5,y10;// 逻辑与两个条件都满足才为真。intcan_drive(age18)has_license;printf(可以开车%d\n,can_drive);// 输出1真。// 逻辑或满足一个条件即为真。intis_young_or_old(age18)||(age65);printf(是年轻人或老年人%d\n,is_young_or_old);// 输出0假。// 逻辑非取反。intno_license!has_license;printf(没有驾照%d\n,no_license);// 输出0假。// 短路求值示例逻辑与左侧为假右侧x不执行。intresult1(x10)(x);printf(result1 %d, x %d\n,result1,x);// 输出0x 5x未执行。// 短路求值示例逻辑或左侧为真右侧y不执行。intresult2(y5)||(y);printf(result2 %d, y %d\n,result2,y);// 输出1y 10y未执行。return0;}4.5 自增和自减运算符⚠️不建议大量使用自增和自减–是单目运算符用于将变量的值 “直接增加 1” 或 “减少 1”分为前缀和后缀两种形式核心区别是 “增减操作” 和 “取值操作” 的执行顺序。运算符描述示例核心区别自增x前缀先自增再取值自增x后缀先取值再自增–自减–x前缀先自减再取值–自减x–后缀先取值再自减 关键注意事项 1、仅适用于变量如5非法x合法因为需要修改变量的值。 2、避免在同一表达式中多次使用如x x结果依赖编译器实现无统一标准易出错。示例#includestdio.hintmain(){intx5,y,z;// 后缀自增先赋值y x5再自增x6。yx;printf(x %d, y %d\n,x,y);// 输出x 6, y 5。x5;// 重置x。// 前缀自增先自增x6再赋值y6。yx;printf(x %d, y %d\n,x,y);// 输出x 6, y 6。// 自减示例。z10;printf(z-- %d\n,z--);// 后缀先取值10再自减z9。printf(z %d\n,z);// 输出9。printf(--z %d\n,--z);// 前缀先自减z8再取值8。return0;}4.6 条件运算符三元运算符⚠️了解即可 条件运算符是 C 语言中唯一的三目运算符语法简洁用于简化二选一的条件判断等价于简单的if-else语句。 语法格式条件表达式 ? 表达式1 : 表达式2。 ● 执行逻辑先判断 “条件表达式” 的真假。 ● 若为真非 0整个表达式的值为 “表达式 1” 的值。 ● 若为假0整个表达式的值为 “表达式 2” 的值。 关键注意事项 1、优先级低于关系运算符和算术运算符高于赋值运算符。 2、结合性为 “右结合”如a ? b : c ? d : e等价于a ? b : (c ? d : e)。 3、表达式 1 和表达式 2 的类型应一致或可隐式转换避免类型不匹配。示例#includestdio.hintmain(){inta10,b20;intmax,min;intnumber15;// 求两个数的最大值等价于 if(ab) maxa; else maxb; 。max(ab)?a:b;printf(较大的数是%d\n,max);// 输出20。// 求两个数的最小值。min(ab)?a:b;printf(较小的数是%d\n,min);// 输出10。// 判断奇偶数。printf(%d是%s\n,number,(number%20)?偶数:奇数);// 输出15是奇数。// 右结合示例a10为真直接返回b20不执行后续判断。intresult(a5)?b:(b15)?30:40;printf(result %d\n,result);// 输出20。return0;}4.7 逗号运算符⚠️了解即可 逗号运算符用于将多个表达式分隔开按从左到右的顺序依次执行整个逗号表达式的值为 “最后一个表达式” 的值。 语法格式表达式1, 表达式2, ..., 表达式n。 ● 执行逻辑先执行表达式 1再执行表达式 2…最后执行表达式 n最终结果为表达式 n 的值。 ● 优先级所有运算符中最低低于赋值运算符如需改变优先级需加括号。 适用场景在允许单个表达式的位置如 for 循环的初始化 / 更新部分执行多个操作。示例#includestdio.hintmain(){inta1,b2,c,d;// 逗号表达式先执行a,再执行b,最终值为b后的结果3。c(a,b,b1);printf(a %d, b %d, c %d\n,a,b,c);// 输出a2, b3, c4。// 无括号时赋值运算符优先级更高先执行c a,再执行b逗号表达式值为b3。a1,b2;// 重置。da,b,b1;printf(a %d, b %d, d %d\n,a,b,d);// 输出a2, b3, d1d a的结果。// for循环中使用初始化a0、b5更新时a、b--。for(inti0;i3;i,a,b--){printf(i %d, a %d, b %d\n,i,a,b);}// 输出// i 0, a 2, b 3// i 1, a 3, b 2// i 2, a 4, b 1return0;}4.8 运算符的优先级与结合性 当一个表达式包含多个运算符时计算顺序由 “优先级” 和 “结合性” 共同决定 —— 优先级决定 “先执行哪个运算符”结合性决定 “优先级相同时的执行顺序”。4.8.1 常见运算符优先级从高到低优先级运算符类别具体运算符1括号()2自增 / 自减单目, --前缀、!、~位非3算术运算符*, /, %乘、除、取模4算术运算符, -加、减5关系运算符, , , 6关系运算符, !相等 / 不等7逻辑运算符逻辑与8逻辑运算符||逻辑或9条件运算符?:10赋值运算符, , -, *, /, %11逗号运算符,4.8.2 结合性规则左结合优先级相同时从左到右执行如算术运算符、关系运算符、逗号运算符。示例a b - c等价于(a b) - ca b 5是例外赋值运算符右结合。右结合优先级相同时从右到左执行如赋值运算符、条件运算符。示例a b 5等价于a (b 5)a ? b : c ? d : e等价于a ? b : (c ? d : e)。核心建议当不确定优先级或结合性时直接用括号明确执行顺序—— 既避免出错又让代码更易读括号优先级最高。示例#includestdio.hintmain(){inta5,b3,c2,result;// 无括号先乘后加优先级* resultab*c;printf(a b * c %d\n,result);// 输出115 3*2// 有括号先加后乘括号改变优先级result(ab)*c;printf((a b) * c %d\n,result);// 输出16(53)*2// 结合性示例赋值运算符右结合intx,y;xy10;// 等价于 x (y 10)printf(x %d, y %d\n,x,y);// 输出10, 10return0;}4.9 位运算符基础 位运算符用于直接操作二进制位适用于整型数据char、int、long 等底层编程如硬件操作、数据压缩中常用基础阶段需掌握核心用法。运算符描述示例二进制结果二进制按位与1010 0111 0010按位或1010 | 0111 1111^按位异或1010 ^ 0111 1101~按位非取反~1010 0101假设 4 位左移1010 1 10100右移1010 1 0101关键说明按位与对应位都为 1 时结果为 1可用于 “清 0 某些位”。按位或|对应位有一个为 1 时结果为 1可用于 “置 1 某些位”。按位异或^对应位不同时结果为 1可用于 “交换变量”“翻转某些位”。左移二进制位向左移动 n 位右边补 0等价于乘以 2^n如a 1等价于a * 2。右移二进制位向右移动 n 位左边补符号位正数补 0负数补 1等价于除以 2^n取整。示例#includestdio.hintmain(){inta10,b7;// a1010二进制b0111二进制printf(a b %d\n,ab);// 0010 → 2printf(a | b %d\n,a|b);// 1111 → 15printf(a ^ b %d\n,a^b);// 1101 → 13printf(~a %d\n,~a);// 按位取反依赖系统位数结果为负数printf(a 1 %d\n,a1);// 10100 → 2010*2printf(a 1 %d\n,a1);// 0101 → 510/2return0;}笔记算术运算符中整数除法会舍弃小数取模仅适用于整型浮点数比较需用 “差值绝对值” 避免精度问题。区分相等判断和赋值这是高频编程错误。逻辑运算符支持 “短路求值”左侧结果可确定时右侧表达式不执行需避免依赖右侧副作用如x。自增 / 自减的前缀和后缀核心区别前缀 “先增减再取值”后缀 “先取值再增减”避免同一表达式多次使用。条件运算符?:简化二选一逻辑结合性为右结合逗号运算符优先级最低结果为最后一个表达式的值。优先级括号 算术 关系 逻辑 条件 赋值 逗号不确定时用括号明确顺序。位运算符直接操作二进制位左移等价于乘 2、右移等价于除 2取整仅适用于整型数据。