• C语言操作符大全(建议收藏)


    前言
    💖作者龟龟不断向前
    简介宁愿做一只不停跑的慢乌龟,也不想当一只三分钟热度的兔子。
    👻专栏C++初阶知识点

    👻工具分享

    1. 刷题: 牛客网 leetcode
    2. 笔记软件:有道云笔记
    3. 画图软件:Xmind(思维导图) diagrams(流程图)

    在这里插入图片描述

    如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持博主🙊,如有不足还请指点,博主及时改正

    C语言操作符

    1.操作符分类

    在这里插入图片描述

     

    2.算术操作符

    +    -   *   /   %
    
    • 1

      1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。

      2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法

    #include
    
    
    int main()
    {
    	printf("%d\n", 3 / 2);//整数除法
    	printf("%.1f\n", 3.0 / 2);//浮点数除法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

      3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

     

    1.1%的应用 – 求解最大公因数

    方法:辗转相除法

    在这里插入图片描述

    #include
    
    int max_common_fac(int m, int n)
    {
    	int r = 0;
    	do
    	{
    		r = m % n;
    		m = n;//m取上一次的除数
    		n = r;//n取上一次的余数
    	} while (r);//直到r为0,此时的除数为最大公因数
    
    	return m;
    }
    
    int main()
    {
    	int m = 0, n = 0;
    	scanf("%d %d", &m, &n);
    
    	int ret = max_common_fac(m, n);
    	printf("%d和%d的最大公因数为%d\n", m, n ,ret);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

     

    1.2%的应用 – 拆出一个数的每一位
    #include
    
    //为了让效果明显一点,咱们将每一位打印出来
    void seq_print(int n)
    {
    	if (n > 9)
    	{
    		seq_print(n / 10);
    	}
    
    	printf("%d ", n % 10);
    	return;
    }
    
    int main()
    {
    	int n = 0;
    	scanf("%d", &n);
    
    	seq_print(n);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

     


     

    3.移位操作符

    << 左移操作符
    >> 右移操作符
    
    • 1
    • 2

    移位移位,移动的是二进制位

    1. 将一个数切换成二进制
    2. 再进行移位

     

    2.1左移

    移位规则:

    左移:左边弃之,右边补0

    在这里插入图片描述

    ps:是b接收了a<<1的值,b为20,但是a还是原来的10,没有变化

     

    2.2右移

    移位规则:

    1. 逻辑移位

    左边用0填充,右边丢弃

    1. 算术移位

    左边用原该值的符号位填充,右边丢弃

    在这里插入图片描述

    ps1:咱们vs编译器的右移使用的是算术右移

    警告⚠ :对于移位运算符,不要移动负数位,这个是标准未定义的。

     

    4.位操作符

    & //按位与 -- 同1为1,否则为0
    | //按位或 -- 同0为0,反则为1
    ^ //按位异或 -- 相同为0,相异为1
    注:他们的操作数必须是整数。
    
    • 1
    • 2
    • 3
    • 4

    ps:位操作符,相对于二进制位的操作

     

    #include
    
    int main()
    {
    	int a = 3;
    	//00000000000000000000000000000011 -- 3的补码
    	int b = -5;
    	//10000000000000000000000000000101
    	//11111111111111111111111111111010
    	//11111111111111111111111111111011 -- -5的补码
    
    	//a&b
    	//00000000000000000000000000000011 -- &之后的结构,符号位是0,原反补一致
    
    	//a|b
    	//11111111111111111111111111111011 -- |之后的结果,此时还是补码,打印出来要转换成原码
    	//10000000000000000000000000000100
    	//10000000000000000000000000000101 -- -5
    
    	//a^b
    	//11111111111111111111111111111000 -- ^之后的结果,此时还是补码,打印出来要转换成原码
    	//10000000000000000000000000000111
    	//10000000000000000000000000001000  -- -8
    
    	printf("a & b = %d\n", a & b);
    	printf("a | b = %d\n", a | b);
    	printf("a ^ b = %d\n", a ^ b);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

     

    4.1&与>>的应用 – 计算出二进制下1的个数

    解题思路:得到二进制下的每一位,如果是1,计数器count+1,最后count的值是二进制中1的个数

    如何得到二进制中的每一位

    1. 通过&1,我们可以得到二进制中的最低位

       

    2. 再配合右移(>>),即可将二进位的每一位都得到

    #include
    
    int main()
    {
    	int a = 0;
    	while ((scanf("%d", &a)) != EOF)//多组测试用例,方便测试
    	{
    		int count = 0;
    
    		for (int i = 0; i < 32; ++i)
    		{
    			if ((a >> i) & 1)
    			{
    				++count;
    			}
    		}
    		printf("%d的二进制的1的个数:%d\n", a, count);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

     

    4.2^的应用 – 不创建临时变量,交换两个数

    根据相同为0,相异为1,^有这样的性质

    性质1:0与一个数异或,得到的是这个数

    0 ^ a = a

    性质2:一个数与其本身异或,得到0

    a ^ a = 0

    性质1和性质2结合:

    a ^ a ^ b = 0

    b ^ b ^ a = 0

    性质3:^具有交换律

    a ^ b = b ^ a

    所以可以得到:

    a ^ b ^ a = b

    a ^ b ^ b = a

    即我们可以将a ^ b看成一个密匙,将密匙与a进行 ^运算得到b,将密匙与b进行 ^运算得到a

     

    #include
    
    int main()
    {
    	int a = 3;
    	int b = 5;
    	a = a^b;//a此时变成密匙
    	b = a^b;//密匙 ^ b = a   b此时变成a
    	a = a^b;//密匙 ^ a = b   a此时变成b
    
    	printf("%d %d\n", a, b);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

     

    5.赋值运算符

    = – 将右操作数赋给做操作数

    例如:

    int a = 10;
    int x = 0;
    int y = 20;
    //也可以连续赋值
    a = x = y+1;//从右向左赋值
    //效果等价于
    x = y+1;
    a = x;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

     

    符合赋值符

    +=
        +=效果举例:
        int x = 10;
    	x = x+10;
    	等价于:
        x += 10;//复合赋值
    -=
    *=
    /=
    %=
    >>=
    <<=
    &=
    |=
    ^=
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

     

    6.单目操作符

    !           逻辑反操作
    -           负值
    +           正值 -- +a -- 对a不做任何处理
    &           取地址
    sizeof      操作数的类型长度(以字节为单位)
    ~           对一个数的二进制按位取反
    --          前置、后置--
    ++          前置、后置++
    *           间接访问操作符(解引用操作符)
    (类型)       强制类型转换
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

     

    #include
    
    int main()
    {
    	int a = 0;
    	int b = 7;
    	printf("!%d = %d\n", a, !a);
    	printf("!%d = %d\n", b, !b);
    
    
    	printf("&a = %p\n", &a);
    	printf("&b = %p\n", &b);
    
    	printf("%u\n", sizeof(int));
    	printf("%u\n", sizeof(a));
    	printf("%u\n", sizeof a);//true
    	//printf("%u\n", sizeof int); //error sizeof后面不接括号,不能接类型名,但是可以接变量名
    	
        printf("%d\n",~0);//-1 -- 二进制的每一位按位取反
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

     

    6.1前置,后置的++ –

    前置:先使用,再++ –

    后置:先++ – ,再使用

     

    前置:

    #include
    
    int main()
    {
    	int a = 10;
    	//后置++
    	int b = a++;//先执行b = a ,再执行a++
    
    	printf("%d\n", b);//10
    
    	printf("%d\n", a);//11
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

     

    #include
    
    int main()
    {
    	int a = 10;
    	//后置++
    	int b = ++a;//先执行a++,后执行b = a
    
    	printf("%d\n", b);//11
    
    	printf("%d\n", a);//11
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    6.2sizeof和数组
    #include 
    
    void test1(int arr[])
    {
    	 printf("%d\n", sizeof(arr));//(2)
    }
    
    void test2(char ch[])
    {
     	printf("%d\n", sizeof(ch));//(4)
    }
    
    int main()
    {
         int arr[10] = {0};
         char ch[10] = {0};
         printf("%d\n", sizeof(arr));//(1)
         printf("%d\n", sizeof(ch));//(3)
         test1(arr);
         test2(ch);
         return 0;
    }
    
    //(1) -- 40
    //(2) -- 10
    //(3) -- 4/8
    //(4) -- 4/8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

     
    在函数调用test1test2中,传过去的arrch数组名,是首元素地址的意义,即形参接收实参其实只是一个指针变量来接收,指针变量的大小只与平台有关,与类型无关

    7.关系操作符

    >
    >=
    <
    <=
    !=   	用于测试“不相等”
    ==      用于测试“相等” -- 注意是两个等号
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

     

    8.逻辑操作符

    &&     逻辑与
    ||     逻辑或
    
    • 1
    • 2

    && 和 ||的理解有很多种

    1. 有些同学理解成botheither
    2. 有些同学理解成并且/都或者
    3. 有些同学理解成电路中的串联并联

    大家用适合自己理解的去理解即可

    在这里插入图片描述

     

    举例1:

    #include
    
    int main()
    {
    	int a = 1;
    	int b = 2;
    	if (a && b)
    	{
    		printf("你们两都来啦\n");
    	}
    	else
    	{
    		printf("你们两怎么没都来");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    int main()
    {
    	int a = 0;
    	int b = 0;
    	if (a || b)
    	{
    		printf("你们两至少有一个来了\n");
    	}
    	else
    	{
    		printf("你们两怎么没有一个人来\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

     

    举例2:

    
    
    int main()
    {
    	int age = 0;
    	printf("请输入你的年龄\n");
    	scanf("%d", &age);
    	//if (18 <= age <= 36)//逻辑相差很大
        if (age >= 18 && age <= 36)
    	{
    		printf("你是青年\n");
    	}
    	else
    	{
    		printf("你不是青年\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里比较容易错,大家如果想要表示一个18-36的范围,千万不要像数学中一样直接来一手18 <= age <= 36,这是一个错误的逻辑,&&是一个二元操作符,一次只能进行两个操作数的操作,无法达到我们一次到位的效果

    正确写法: if (age >= 18 && age <= 36)

     


     

    8.1&& 与 ||的短路问题

    360笔试题

    #include 
    int main()
    {
        int i = 0,a=0,b=2,c =3,d=4;
        i = a++ && ++b && d++;
        //i = a++||++b||d++;
        printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

     

    修改:

    #include 
    int main()
    {
        int i = 1,a=0,b=2,c =3,d=4;
        i = a++||++b||d++;
        printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

     

    短路条件:

    &&:当遇到假时,后面的表达式便不再执行

    ||:当遇到真时,后面的表达式便不再执行

     

    9.条件操作符

    ​ 下面的图片可以大致解释条件表达式的意思

    龟龟小故事:小明和小刚同时爱上了小红,小红也不知道怎么选择,于是绝对让小明和小刚做一个竞争,

    小明赢了,那么小红就选择小明,小明输了(小刚赢了),小红就选择小刚

    在这里插入图片描述

    在这里插入图片描述

    代码举例:

    #include
    
    int main()
    {
    	int a = 3;
    	int b = 10;
    	int c = a > b ? a : b;
    	printf("c = %d\n", c);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    上述代码中,如果 a > b,则c = a,否则 c = b

     


     

    正经解释:

    条件表达式也叫做三目表达式,因为操作数有三个

    exp1?exp2:exp3,如果exp1表达式的值为真,那么整个表达式的值就是exp2的值,否则整个表达式的值就是exp3的值

     

    所以我们的求两数的最大值的函数可以稍微改善一下了:

    改善前:

    int Max(int x, int y)
    {
    	if (x > y)
    	{
    		return x;
    	}
    	else
    	{
    		return y;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

     

    改善后:

    int Max(int x, int y)
    {
    	return x > y ? x : y;
    }
    
    • 1
    • 2
    • 3
    • 4

     


    龟龟小故事的结局与条件表达式无关😅
    由于龟龟故事的结局有一点点大转变,审核警告我说我有点狂,所以大家可以去我仓库看龟龟小故事结局

     

    10.逗号表达式

    exp1, exp2, exp3, …expN
    
    • 1

     

    逗号表达式,就是用逗号隔开的多个表达式。

    逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果

    ps:由于逗号表达式是所有表达式中,优先级最低的,咱们尽量加上括号

    (exp1, exp2, exp3, …expN)
    
    • 1
    #include
    
    int main()
    {
    	int a = 1;
    	int b = 2;
    	int c = (a>b, a = b + 10, a, b = a + 1);
    	printf("%d\n", c);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

     

    ###11下标引用、函数调用和结构成员

    • [] – 下标引用操作符

      语法:数组名 + [下标]

    操作数:数组名 + 下标值

    #include
    
    int main()
    {
        int arr[10];//创建数组
         arr[9] = 10;//实用下标引用操作符。
         //[ ]的两个操作数是arr和9。
        printf("%d\n",arr[9]);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

     

    • () – 函数调用操作符

      语法: 函数名 + (n个函数参数)

    操作数:函数名 + 参数 (所以操作数至少有一个函数名)

    #include 
     void test1()
     {
    	 printf("你好\n");
     }
    
     void test2(const char *str)
     {
     	printf("%s\n", str);
     }
    
     int main()
     {
         test1();            //实用()作为函数调用操作符。
         test2("hello world");//实用()作为函数调用操作符。
         return 0;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

     

    • 访问一个结构的成员

      .结构体.成员名

      -> 结构体指针->成员名

      #include 
      struct Stu
      {
           char name[10];
           int age;
           char sex[5];
           double score;
      };
          
      void set_age1(struct Stu stu)
      {
       	stu.age = 18;
      }
      
      void set_age2(struct Stu* pStu)
      {
      	 pStu->age = 18;//结构成员访问
      }
      
      int main()
      {
           struct Stu stu;
           struct Stu* pStu = &stu;//结构成员访问
      
           stu.age = 20;//结构成员访问
           set_age1(stu);//值传递
      
           pStu->age = 20;//结构成员访问
           set_age2(pStu);//址传递
           return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31

       

    12.操作符的属性

    1. 操作符的优先级
    2. 操作符的结合性
    3. 是否控制求值顺序。

    两个相邻的操作符先执行哪个?取决于他们的优先级。

    如果两者的优先级相同,取决于他们的结合性

    会控制求值顺序的操作符有:&& , || 逗号表达式,三目表达式

    && ||的短路会使每次的表达式求值顺序不一样

    关于优先级,大家可以参考这张操作符优先级表

     

    12.1编译器也无法知晓的表达式求值

    ps:即使有了优先级,结合性,控制求值顺序这些属性,并不就意味着所有的表达式求值都有了一致的求法,代码的不规范,还是会造成编译器也不知该如何处理的情况

    #include
    
    int main()
    {
     int i = 10;
     i = i-- - --i * ( i = -3 ) * i++ + ++i;
     printf("i = %d\n", i);
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

     

    《c和指针》这本书中,作者将改代码放在不同的编译器下跑的结果:

    在这里插入图片描述

    所以咱们还是要写出一些规范的代码,不然编译器也要一个头,两个大了

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    揭秘一线大厂Redis面试高频考点(3万字长文、吐血整理)
    docker for windonws--Windows 10 家庭中文版安装apache zeppelin 0.10.1版本及安全配置
    PGsql设置自增ID
    数据结构·单链表
    leetcode第361场周赛补题
    Linux线程安全
    c++运算符重载
    把react元素转成dom元素
    【漏洞复现】Progress Flowmon 命令注入漏洞CVE-2024-2389
    System V 消息队列(一)—— 消息队列相关接口函数(msgget / msgctl)
  • 原文地址:https://blog.csdn.net/m0_64361907/article/details/127882415