HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • C 语言入门教程

    • C语言系列教程
    • 第01章 基础概念与编译
    • 第02章 数据类型与变量
    • 第03章 运算符
    • 第04章 输入输出
    • 第05章 流程控制
    • 第06章 数组
    • 第07章 指针
    • 第08章 函数
    • 第09章 构造类型

第03章 运算符

3.1 运算符分类

C语言的运算符按功能分类:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 条件运算符
  • 其他运算符

3.2 算术运算符

3.2.1 基本算术运算符

运算符说明示例结果
+加法5 + 38
-减法5 - 32
*乘法5 * 315
/除法5 / 31 (整数除法)
%取模(余数)5 % 32

3.2.2 整数除法与浮点除法

#include <stdio.h>

int main()
{
    int a = 5, b = 2;
    float c = 5.0, d = 2.0;

    printf("整数除法: %d\n", a / b);       // 5 / 2 = 2
    printf("浮点除法: %f\n", c / d);       // 5.0 / 2.0 = 2.5
    printf("混合除法: %f\n", (float)a / b); // 2.5

    return 0;
}

3.2.3 自增自减运算符

#include <stdio.h>

int main()
{
    int a = 10, b = 10;

    printf("a++ = %d\n", a++);  // 先使用后加: 输出10, a变11
    printf("a = %d\n", a);      // 11

    printf("++b = %d\n", ++b);  // 先加后使用: b变11,输出11
    printf("b = %d\n", b);      // 11

    return 0;
}

3.3 关系运算符

运算符说明示例结果
==等于5 == 30 (假)
!=不等于5 != 31 (真)
>大于5 > 31
<小于5 < 30
>=大于等于5 >= 51
<=小于等于3 <= 51
#include <stdio.h>

int main()
{
    int a = 5, b = 3;

    printf("a == b: %d\n", a == b);  // 0
    printf("a != b: %d\n", a != b);  // 1
    printf("a > b:  %d\n", a > b);   // 1
    printf("a < b:  %d\n", a < b);   // 0

    return 0;
}

⚠️ 常见错误: 混淆=(赋值)和==(比较)

int a = 10;
if (a = 5)  // 错误!这是赋值,不是比较
{
    printf("a = %d\n", a);  // 总是执行,输出5
}

if (a == 5)  // 正确!这才是比较
{
    printf("a equals 5\n");
}

3.4 逻辑运算符

运算符说明示例结果
&&逻辑与(AND)(5>3) && (2<4)1
||逻辑或(OR)(5<3) || (2<4)1
!逻辑非(NOT)!(5>3)0

3.4.1 短路特性

逻辑与(&&)的短路:

#include <stdio.h>

int main()
{
    int a = 5, b = 0;

    // 当第一个条件为假时,不会计算第二个条件
    if (b != 0 && a / b > 2)
    {
        printf("条件成立\n");
    }
    else
    {
        printf("条件不成立\n");  // 输出这个
    }

    return 0;
}

逻辑或(||)的短路:

#include <stdio.h>

int func1()
{
    printf("func1被调用\n");
    return 1;
}

int func2()
{
    printf("func2被调用\n");
    return 0;
}

int main()
{
    if (func1() || func2())  // func1返回真,不会调用func2
    {
        printf("条件成立\n");
    }

    return 0;
}

输出:

func1被调用
条件成立

3.5 位运算符

3.5.1 位运算符列表

运算符说明示例二进制示例
&按位与5 & 30101 & 0011 = 0001
|按位或5 | 30101 | 0011 = 0111
^按位异或5 ^ 30101 ^ 0011 = 0110
~按位取反~5~0101 = 1010
<<左移5 << 10101 << 1 = 1010
>>右移5 >> 10101 >> 1 = 0010

3.5.2 位运算基础

#include <stdio.h>

int main()
{
    unsigned int a = 5;   // 0000 0101
    unsigned int b = 3;   // 0000 0011

    printf("a & b = %u\n", a & b);   // 0001 = 1
    printf("a | b = %u\n", a | b);   // 0111 = 7
    printf("a ^ b = %u\n", a ^ b);   // 0110 = 6
    printf("~a = %u\n", ~a);         // 1111...1010
    printf("a << 1 = %u\n", a << 1); // 1010 = 10
    printf("a >> 1 = %u\n", a >> 1); // 0010 = 2

    return 0;
}

3.5.3 位运算的应用

1. 将第n位置1

int setBit(int num, int n)
{
    return num | (1 << n);
}

int main()
{
    int num = 0;           // 0000 0000
    num = setBit(num, 2);  // 0000 0100 = 4
    printf("%d\n", num);   // 4

    return 0;
}

2. 将第n位置0

int clearBit(int num, int n)
{
    return num & ~(1 << n);
}

int main()
{
    int num = 7;            // 0000 0111
    num = clearBit(num, 1); // 0000 0101 = 5
    printf("%d\n", num);    // 5

    return 0;
}

3. 测试第n位

int testBit(int num, int n)
{
    return (num & (1 << n)) != 0;
}

int main()
{
    int num = 5;  // 0000 0101

    printf("第0位: %d\n", testBit(num, 0));  // 1
    printf("第1位: %d\n", testBit(num, 1));  // 0
    printf("第2位: %d\n", testBit(num, 2));  // 1

    return 0;
}

4. 交换两个变量(不使用临时变量)

#include <stdio.h>

int main()
{
    int a = 5, b = 3;

    printf("交换前: a=%d, b=%d\n", a, b);

    a = a ^ b;
    b = a ^ b;  // b = (a^b)^b = a
    a = a ^ b;  // a = (a^b)^a = b

    printf("交换后: a=%d, b=%d\n", a, b);

    return 0;
}

3.6 赋值运算符

3.6.1 基本赋值

int a = 10;  // 基本赋值

3.6.2 复合赋值运算符

运算符等价形式示例
+=a = a + ba += 3
-=a = a - ba -= 3
*=a = a * ba *= 3
/=a = a / ba /= 3
%=a = a % ba %= 3
&=a = a & ba &= 3
|=a = a | ba |= 3
^=a = a ^ ba ^= 3
<<=a = a << ba <<= 3
>>=a = a >> ba >>= 3
#include <stdio.h>

int main()
{
    int a = 10;

    a += 5;  // a = a + 5 = 15
    printf("a = %d\n", a);

    a *= 2;  // a = a * 2 = 30
    printf("a = %d\n", a);

    a /= 3;  // a = a / 3 = 10
    printf("a = %d\n", a);

    return 0;
}

3.7 条件运算符(三目运算符)

语法

条件 ? 表达式1 : 表达式2

如果条件为真,返回表达式1的值;否则返回表达式2的值。

示例

#include <stdio.h>

int main()
{
    int a = 10, b = 20;
    int max;

    max = (a > b) ? a : b;
    printf("max = %d\n", max);  // 20

    // 等价于:
    if (a > b)
        max = a;
    else
        max = b;

    return 0;
}

嵌套使用

#include <stdio.h>

int main()
{
    int score = 85;
    char grade;

    grade = (score >= 90) ? 'A' :
            (score >= 80) ? 'B' :
            (score >= 70) ? 'C' :
            (score >= 60) ? 'D' : 'F';

    printf("成绩等级: %c\n", grade);  // B

    return 0;
}

3.8 其他运算符

3.8.1 sizeof运算符

sizeof(类型)
sizeof 表达式
#include <stdio.h>

int main()
{
    int a = 10;
    int arr[10];

    printf("int: %lu\n", sizeof(int));      // 4
    printf("a: %lu\n", sizeof(a));          // 4
    printf("arr: %lu\n", sizeof(arr));      // 40
    printf("arr[0]: %lu\n", sizeof(arr[0])); // 4

    return 0;
}

3.8.2 逗号运算符

表达式1, 表达式2, ..., 表达式n

从左到右依次计算,返回最后一个表达式的值。

#include <stdio.h>

int main()
{
    int a, b, c;

    a = (b = 3, c = 5, b + c);  // a = 8
    printf("a = %d\n", a);

    return 0;
}

3.8.3 取址运算符 &

int a = 10;
int *p = &a;  // 取a的地址

3.8.4 解引用运算符 *

int a = 10;
int *p = &a;
printf("%d\n", *p);  // 输出a的值:10

3.9 运算符优先级

优先级从高到低:

优先级运算符结合性
1() [] -> .左→右
2! ~ ++ -- + - * & sizeof右→左
3* / %左→右
4+ -左→右
5<< >>左→右
6< <= > >=左→右
7== !=左→右
8&左→右
9^左→右
10|左→右
11&&左→右
12||左→右
13?:右→左
14= += -= *= /= %= &= ^= |= <<= >>=右→左
15,左→右

优先级示例

#include <stdio.h>

int main()
{
    int a = 5, b = 3, c = 2;

    int result1 = a + b * c;      // 5 + (3*2) = 11
    int result2 = (a + b) * c;    // (5+3) * 2 = 16
    int result3 = a > b && b > c; // (5>3) && (3>2) = 1

    printf("result1 = %d\n", result1);
    printf("result2 = %d\n", result2);
    printf("result3 = %d\n", result3);

    return 0;
}

3.10 实践练习

练习1: 位运算实现权限系统

#include <stdio.h>

#define READ    (1 << 0)  // 0001
#define WRITE   (1 << 1)  // 0010
#define EXECUTE (1 << 2)  // 0100

int main()
{
    int permission = 0;

    // 添加权限
    permission |= READ;
    permission |= WRITE;

    // 检查权限
    if (permission & READ)
        printf("有读权限\n");

    if (permission & WRITE)
        printf("有写权限\n");

    if (permission & EXECUTE)
        printf("有执行权限\n");
    else
        printf("无执行权限\n");

    // 删除权限
    permission &= ~WRITE;

    printf("\n删除写权限后:\n");
    if (permission & WRITE)
        printf("有写权限\n");
    else
        printf("无写权限\n");

    return 0;
}

练习2: 判断奇偶数

#include <stdio.h>

int main()
{
    int num = 15;

    // 使用位运算判断奇偶
    if (num & 1)
        printf("%d是奇数\n", num);
    else
        printf("%d是偶数\n", num);

    return 0;
}

练习3: 计算2的幂次

#include <stdio.h>

int main()
{
    int n = 10;

    // 2^n = 1 << n
    printf("2^%d = %d\n", n, 1 << n);  // 1024

    return 0;
}

3.11 常见错误

错误1: 赋值与比较混淆

int a = 10;
if (a = 5)  // 错误!应该是 a == 5
{
    printf("a = %d\n", a);
}

错误2: 逻辑运算符与位运算符混淆

int a = 5, b = 3;

// 逻辑与
if (a && b)  // 正确:逻辑运算
    printf("both are true\n");

// 位与
if (a & b)   // 可能不是你想要的
    printf("bitwise AND result is non-zero\n");

错误3: 除零错误

int a = 10, b = 0;
int c = a / b;  // 运行时错误:除数为0

防御性编程:

if (b != 0)
{
    int c = a / b;
}
else
{
    printf("除数不能为0\n");
}

3.12 小结

本章学习了:

算术运算符(+, -, *, /, %, ++, --) 关系运算符(==, !=, <, >, <=, >=) 逻辑运算符(&&, ||, !)及其短路特性 位运算符(&, |, ^, ~, <<, >>)及其应用 赋值运算符(=, +=, -=等) 条件运算符(?😃 运算符优先级和结合性

重点提示:

  1. 注意区分=(赋值)和==(比较)
  2. 利用逻辑运算符的短路特性避免错误
  3. 位运算在底层编程和优化中非常有用
  4. 复杂表达式使用括号明确优先级
  5. 避免除零错误

上一章: 第02章 数据类型与变量下一章: 第04章 输入输出

Prev
第02章 数据类型与变量
Next
第04章 输入输出