史上最详细的C语言--操作符详解,没有之一。

目录

  1. 算术操作符:数学运算的基石
  2. 移位操作符:二进制世界的搬运工
  3. 位操作符:精准操控每一位
  4. 赋值与复合赋值操作符:高效修改变量
  5. 单目操作符:一元操作的魔法
  6. 关系与逻辑操作符:构建条件逻辑
  7. 条件与逗号表达式:灵活控制流程
  8. 下标引用与函数调用:操作符的扩展应用
  9. 隐式类型转换:编译器的“自动修正”
  10. 表达式求值与操作符优先级:避免陷阱的关键
  11. 实战案例:经典问题的操作符实现
  12. 总结与最佳实践

1. 算术操作符:数学运算的基石

算术操作符包括 +-*/%,用于执行基本数学运算。

关键点解析:
  • 整数除法 vs 浮点除法

    int a = 7 / 3;     // 结果:2(整数除法,丢弃小数部分)
    float b = 7.0 / 3; // 结果:2.333333(浮点除法)
    

    陷阱:若两个整数相除,结果仍为整数,需显式转换类型以保留小数。

  • 取模操作符 % 的限制

    int c = 7 % 3;      // 结果:1(余数)
    // int d = 7 % 3.0; // 错误:操作数必须为整数
    

    应用场景:判断奇偶性、循环缓冲区索引计算。


2. 移位操作符:二进制世界的搬运工

移位操作符 <<(左移)和 >>(右移)直接操作二进制位。

左移操作符 <<
  • 规则:高位丢弃,低位补0。
    int a = 5;          // 二进制 00000101
    int b = a << 2;     // 左移两位 → 00010100(十进制20)
    
右移操作符 >>
  • 逻辑右移 vs 算术右移
    • 逻辑右移:高位补0(适用于无符号数)。
    • 算术右移:高位补符号位(适用于有符号数,保留正负性)。
    int c = -8;         // 补码:11111111111111111111111111111000
    int d = c >> 1;     // 算术右移 → 11111111111111111111111111111100(十进制-4)
    
注意事项:
  • 移位负数位是未定义行为
    int e = 10 >> -1;   // 未定义行为,编译器可能报错或产生不可预测结果
    

3. 位操作符:精准操控每一位

位操作符包括 &(按位与)、|(按位或)、^(按位异或)。

按位与 &
  • 应用:掩码操作、清零特定位。
    int a = 0b1100;     // 12
    int mask = 0b1010;  // 10
    int b = a & mask;   // 0b1000(8)
    
按位异或 ^
  • 特性:相同位为0,不同位为1。
    应用:交换变量值、数据加密。
    int x = 10, y = 20;
    x = x ^ y;          // x = 10 ^ 20
    y = x ^ y;          // y = 10 ^ 20 ^ 20 → 10
    x = x ^ y;          // x = 10 ^ 20 ^ 10 → 20
    
按位或 |
  • 应用:设置特定位为1。
    int flags = 0b0000;
    flags |= 0b1001;    // 设置第0位和第3位为1 → 0b1001(9)
    

4. 赋值与复合赋值操作符:高效修改变量

赋值操作符 = 可与算术或位操作符结合,形成复合赋值符。

示例:
int a = 10;
a += 5;       // 等价于 a = a + 5 → 15
a <<= 1;      // 左移一位 → 30
a &= 0x0F;    // 按位与掩码 → 14(0x0E)
注意事项:
  • 连续赋值的可读性问题
    int x = y = z = 0;  // 合法但可读性差
    // 推荐分开赋值:int x=0, y=0, z=0;
    

5. 单目操作符:一元操作的魔法

单目操作符仅需一个操作数,包括 !~++--sizeof 等。

自增与自减操作符
  • 前置 vs 后置
    int a = 10;
    int b = a++;   // b=10, a=11(后置:先赋值,后自增)
    int c = ++a;   // c=12, a=12(前置:先自增,后赋值)
    
sizeof 操作符
  • 计算变量或类型的大小
    printf("int size: %zu\n", sizeof(int));    // 输出4(32/64位系统可能不同)
    int arr[10];
    printf("array size: %zu\n", sizeof(arr));  // 输出40(假设int为4字节)
    
按位取反 ~
  • 二进制取反操作
    int a = 0;      // 二进制全0
    int b = ~a;     // 二进制全1 → -1(补码表示)
    

6. 关系与逻辑操作符:构建条件逻辑

关系操作符(>, >=, <, <=, ==, !=)和逻辑操作符(&&, ||)用于条件判断。

短路求值特性:
  • && 的短路特性:若左操作数为假,右操作数不执行。

    int a = 0, b = 1;
    if (a++ && b++) { /* 不执行 */ }
    // a=1, b=1(因a初始为0,右操作数b++未执行)
    
  • || 的短路特性:若左操作数为真,右操作数不执行。

    if (a++ || b++) { /* 执行 */ }
    // a=2, b=1(a++为1,触发短路)
    

7. 条件与逗号表达式:灵活控制流程

条件操作符 ?:
  • 简化条件赋值
    int max = (a > b) ? a : b;  // 取a和b中的较大值
    
逗号表达式
  • 从左到右求值,结果为最后一个表达式
    int d = (c = 5, a = c + 3, b = a - 4, c += 5);  // d=10
    

8. 下标引用与函数调用:操作符的扩展应用

下标引用 []
  • 访问数组元素
    int arr[5] = {1, 2, 3, 4, 5};
    arr[2] = 10;  // 修改第三个元素
    
函数调用 ()
  • 传递参数与执行函数
    int add(int x, int y) { return x + y; }
    int result = add(3, 5);  // 调用函数,result=8
    

9. 隐式类型转换:编译器的“自动修正”

整型提升
  • charshort 在运算时提升为 int
    char a = 3, b = 127;
    char c = a + b;  // 整型提升后计算,结果为-126(二进制截断)
    
算术转换规则
  • 低精度向高精度转换
    int a = 5;
    float b = 3.14;
    float sum = a + b;  // a隐式转换为float
    

更加详细的隐式类型转换内容:隐式类型转换详解

10. 表达式求值与操作符优先级:避免陷阱的关键

以下是整理后的表格:
以下是补充说明后的完整表格,包含 rexp(右值表达式)lexp(左值表达式)结合性(L-R/R-L/N/A) 以及 是否控制求值顺序 的详细解释:


C/C++ 操作符属性表

操作符描述用法示例结果类型结合性是否控制求值顺序备注
()聚组(表达式)与表达式同N/A强制优先级,不改变求值顺序。
()函数调用rexp(rexp, ..., rexp)rexpL-R参数求值顺序未定义(C/C++标准未规定)。
[]下标引用rexp[rexp]lexpL-R等价于 *(rexp + rexp)
.访问结构成员lexp.member_namelexpL-Rlexp 必须是左值(如结构体变量)。
->访问结构指针成员rexp->member_namelexpL-Rrexp 必须是指向结构体的指针。
++后缀自增lexp++rexpL-R返回自增前的值,lexp 需为可修改左值。
--后缀自减lexp--rexpL-R返回自减前的值。
!逻辑反!rexprexpR-Lrexp 转换为布尔值后取反。
~按位取反~rexprexpR-L按位取反操作。
+单目,表示正值+rexprexpR-L通常无实际效果,用于类型提升。
-单目,表示负值-rexprexpR-L算术负值。
++前缀自增++lexprexpR-L返回自增后的值。
--前缀自减--lexprexpR-L返回自减后的值。
*间接访问*rexplexpR-Lrexp 必须是指针。
&取地址&lexprexpR-L返回 lexp 的地址。
sizeof取其长度(字节)sizeof rexpsizeof(类型)rexpR-L编译时计算,不求值 rexp(如 sizeof(++x) 不会自增 x)。
(类型)类型转换(类型)rexprexpR-L强制类型转换。
*乘法rexp * rexprexpL-R算术乘法。
/除法rexp / rexprexpL-R整数除法会截断小数部分。
%整数取余rexp % rexprexpL-R操作数必须为整数。
+加法rexp + rexprexpL-R算术加法或指针偏移(如 ptr + 1)。
-减法rexp - rexprexpL-R算术减法或指针偏移。
<<左移位rexp << rexprexpL-R逻辑左移,低位补 0。
>>右移位rexp >> rexprexpL-R算术右移(有符号数补符号位)或逻辑右移(无符号数补 0)。
>大于rexp > rexprexpL-R返回布尔值。
>=大于等于rexp >= rexprexpL-R返回布尔值。
<小于rexp < rexprexpL-R返回布尔值。
<=小于等于rexp <= rexprexpL-R返回布尔值。
==等于rexp == rexprexpL-R返回布尔值。
!=不等于rexp != rexprexpL-R返回布尔值。
&位与rexp & rexprexpL-R按位与操作。
^位异或rexp ^ rexprexpL-R按位异或操作。
|位或rexp | rexprexpL-R按位或操作(注意 | 需转义)。
&&逻辑与rexp && rexprexpL-R短路求值:若左操作数为 false,右操作数不求值。
||逻辑或rexp || rexprexpL-R短路求值:若左操作数为 true,右操作数不求值。
?:条件操作符rexp ? rexp : rexprexpN/A仅求值一侧:根据 rexp 的真假决定求值第二个或第三个表达式。
=赋值lexp = rexprexpR-Llexp 必须是可修改左值。
+= -=复合赋值lexp += rexprexpR-L等价于 lexp = lexp + rexp(其他复合赋值类似)。
,逗号rexp, rexprexpL-R顺序求值:先求值左操作数,再求值右操作数,返回右操作数的结果。

关键说明

  1. lexp(左值表达式)

    • 表示可被赋值的对象(如变量、数组元素、解引用指针等)。
    • 例如:a, *ptr, arr[0]
  2. rexp(右值表达式)

    • 表示临时值或不可被赋值的表达式(如常量、算术结果、函数返回值等)。
    • 例如:1, a + b, func()
  3. 结合性

    • L-R(从左到右):如 a + b + c 等价于 (a + b) + c
    • R-L(从右到左):如 *ptr++ 等价于 *(ptr++)(因 ++ 优先级高于 * 但结合性为 R-L)。
  4. 求值顺序控制

    • &&||?:, 明确控制求值顺序(短路求值或顺序求值)。
    • 其他操作符的求值顺序未定义(如 f() + g()fg 的调用顺序不确定)。

此表格可用于快速查阅操作符的优先级、结合性和求值规则,适合编程参考或面试准备。

操作符优先级表(部分)
示例分析:
int result = a + b * c;  // 先计算b*c,再与a相加
int flag = a & b == c;   // 等价于a & (b == c),可能非预期!

11. 实战案例:经典问题的操作符实现

案例1:求二进制中1的个数
int count_ones(int n) {
    int count = 0;
    while (n) {
        n &= (n - 1);  // 每次消除最右侧的1
        count++;
    }
    return count;
}
// 示例:n=7(0b0111) → 3个1
案例2:矩阵转置
void transpose(int n, int m, int src[n][m], int dest[m][n]) {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            dest[j][i] = src[i][j];  // 行列交换
        }
    }
}
案例3:水仙花数判断
int is_narcissistic(int num) {
    int n = 0, sum = 0, tmp = num;
    while (tmp) { n++; tmp /= 10; }  // 计算位数
    tmp = num;
    while (tmp) {
        sum += pow(tmp % 10, n);
        tmp /= 10;
    }
    return sum == num;
}
// 示例:153 = 1³ + 5³ + 3³ → 是水仙花数

操作符并不需要记忆,作为一个小白熟悉比记忆更加重要,通过大量的代码练习,就可以通过熟能生巧,灵活运用操作符了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值