《C语言运算符100例》优先级面试错题

在这里插入图片描述

一、前言

  运算符优先级一直是让人头疼的东西,趁着 字节取消大小周 的势头来临,通宵整理了一个思维导图出来,希望对你有所帮助。这篇文章,我会仔细分析这张思维导图。
  所有的 C语言运算符的用法都在这里了,并且还有优先级的例子解析,总共 100 道题都在这篇文章里了,激(累)动(死)人(我)心(了)

二、运算符简介

  • 运算符用于执行程序代码运算,会针对一个或几个操作数来进行运算。例如:1 / 2,其操作数是 1 和 2,而运算符则是 “/”(除号)。
  • C语言把除了 控制语句输入输出 以外的几乎所有的基本操作都作为运算符处理,可见其重要性。这么说来,学会了运算符的计算,就等于学会了C语言的 1 / 3,当然这是不可能的!

三、运算符概览

1、按功能分类

  • 按照功能分类,可以分为:后缀运算符、单目运算符、算术运算符、关系运算符、位运算符、逻辑运算符、条件运算符、赋值运算符、逗号运算符。
  • 本文会对这几大类的运算符的优先级进行一个全面的讲解,然后再引入 100 道例题 ,花 1个小时的时间,彻底掌握运算符的优先级问题吧。
  • 想要原题文件的同学,可以 想尽一切办法,找到作者的微信,威逼利诱让他交出来!

2、按操作数个数分类

1)单目运算符

  • 单目运算符(也可以叫一元运算符),是指运算表达式中只有一个操作数的运算符。
  • 1)位运算符中的按位取反 ~,用法诸如:~a~(a + b)
  • 有关于 按位取反 的具体功能,可以参考如下文章:光天化日学C语言(17)- 位运算 ~ 的应用
  • 2)逻辑运算符中的非!,用法诸如:!a!(a + b)
  • 有关 非运算 的具体功能,可以参考如下文章:光天化日学C语言(11)- 逻辑运算符
  • 3)甚至 类型转换(type)也是一种单目运算符,用法诸如:(int)a(int)(a + b)
  • 有关类型转换的具体功能,可以参考如下文章:光天化日学C语言(12)- 类型转换
  • 当然,还有很多,这里就不一一列举了,再讲 运算符优先级和结合性 时,我们会一个一个进行举例。

2)双目运算符

  • 双目运算符(也可以叫二元运算符),是指运算表达式中有两个操作数的运算符。
  • 1)算术运算符中的加 / 减 / 乘 / 除 / 取模(+-*/%),都是双目运算符,用法诸如:a + ba * ba - ba % b
  • 有关 算术运算符 的具体功能,可以参考如下文章:光天化日学C语言(09)- 算术运算符
  • 2)关系运算符中的 ==<=>也都是双目运算符,用法诸如:a > ba <= ba != ba == b
  • 有关 关系运算符 的具体功能,可以参考如下文章:光天化日学C语言(10)- 关系运算符
  • 3)当然逻辑运算符也有双目的。

3)三目运算符

  • 三目运算符(也可以叫三元运算符),是指运算表达式中有三个操作数的运算符。
  • 在C语言中只有一个三目运算符,它叫条件表达式,表示为 ?:,考虑这样一句话:
    if(a + b > 5) {
        a++;
    }else {
        b++;
    }
  • 可以表示成如下一句话:
    a + b > 5 ? a++ : b++;
  • 这是C语言比较独特的语法糖,能够大大节省代码量。

四、运算符优先级和结合性

  • 优先级可以认为是大分类,优先级不同的运算符,按照优先级高的优先计算。结合性可以认为是小分类,优先级相同的运算符,按照结合性进行计算,结合性只有两种:从左到右 和 从右到左。接下来,我们就围绕优先级和结合性来讨论下上述按照功能分类的运算符吧。

1、后缀运算符

运算符名称形式举例1举例2
[]数组下标数组名[常量表达式]a[2]a[2][3]
()圆括号(表达式) 或 函数名(形参表)(a+1)fun(x,y,z)
.对象的成员选择对象.成员名a.ba.b.c
->指针的成员选择指针.成员名a->ba->b->c

2、单目运算符

运算符名称形式举例1举例2
+正号+表达式+5+a[3]
-负号-表达式-5-a[3]
(type)强制类型转换(数据类型)表达式(int)a(int)a[0]
++自增运算符++变量名 / 变量名++++ii++
--自增运算符–变量名 / 变量名–--ii--
!逻辑非!表达式!a[0]!a[0]++
~按位取反~表达式~a~~a
&取地址&变量名&a&(a+1)
*解引用*指针变量名*a*(a+1)
sizeof取长度sizeof(表达式)sizeof(a)sizeof(a + b)

3、算术运算符

运算符名称形式举例1举例2
*表达式 * 表达式3 * 53 * a
/表达式 / 表达式3 / 53 / 5.0
%整型表达式 % 整型非零表达式3 % 5b % -1
运算符名称形式举例1举例2
+表达式 + 表达式a + b(a++) + b
-表达式 - 表达式a - ba - b--

4、移位运算符

运算符名称形式举例1举例2
<<左移变量<<表达式1<<51<<(i+j)
>>右移变量>>表达式x>>1x>>a

5、关系运算符

运算符名称形式举例1举例2
<小于表达式<表达式1 < 2x < y
<=小于等于表达式<=表达式1 <= 2x <= y
>大于表达式>表达式1 > 2x > y
>=大于等于表达式>=表达式1 >= 2x >= y
运算符名称形式举例1举例2
==等于表达式==表达式1 == 2x == y
!=不等于表达式!=表达式1 != 2x != y

6、双目位运算符

运算符名称形式举例1举例2
&等于表达式&表达式1 & 2x & y
^等于表达式^表达式1 ^ 2x ^ y
|等于表达式\表达式1 | 2x | y

7、双目逻辑运算符

运算符名称形式举例1举例2
&&逻辑与表达式&&表达式a && ba + 5 && b + 5
||逻辑与表达式||表达式a || ba + 5 || b + 5

8、条件运算符

运算符名称形式举例1举例2
?:条件运算符表达式1? 表达式2: 表达式3a>b?a:ba<b?a:b

9、赋值运算符

运算符名称形式举例1举例2
=赋值变量=表达式a = ba = 1
+=加后赋值变量+=表达式a += ba += 1
-=减后赋值变量-=表达式a -= ba -= 1
*=乘后赋值变量*=表达式a *= ba *= 1
/=除后赋值变量/=表达式a /= ba /= 1
%=模后赋值变量%=表达式a %= ba %= 1
>>=右移后赋值变量>>=表达式a >>= ba >>= 1
<<=左移后赋值变量<<=表达式a <<= ba <<= 1
&=位与后赋值变量&=表达式a &= ba &= 1
^=异或后赋值变量^=表达式a ^= ba ^= 1
|=位或后赋值变量|=表达式a |= ba |= 1

10、逗号运算符

运算符名称形式举例1举例2
,逗号运算符表达式1,表达式2,…a+b,a-ba||b,a&b
  • 了解逗号表达式的优先级最低以后,我们就可以通过,将语句分隔,而无需添加多余的括号了。

五、运算符优先级和结合性总结

1、结合性

结合方向只有 3 个是 从右往左,其余都是 从左往右(比较符合人的直观感受)。
  (1)一个是单目运算符;
  (2)一个是双目运算符中的 赋值运算符;
  (3)一个条件运算符,也就是C语言中唯一的三目运算符。

2、优先级

后缀运算符和单目运算符优先级一般最高,逗号运算符的优先级最低。快速记忆如下:

单目逻辑运算符 > 算术运算符 > 关系运算符 > 双目逻辑运算符 > 赋值运算符

六、运算符优先级面试错题100例


🧡例题1🧡
#include <stdio.h>
int a[2][2] = { {0, 1}, {2, 3}};
int main() {
    printf("%d\n", a[1][0]);
    return 0;
}

【运行结果】2
【结果答疑】这个例子体现的是下标运算符[]的结合性是从左到右的。


🧡例题2🧡
#include <stdio.h>
int a[5] = {1, 2, 3, 4, 5};
int main() {
    printf("%d\n", a[a[a[a[0]]]]);
    return 0;
}

【运行结果】4
【结果答疑】这个例子体现的是下标运算符[]的嵌套应用,从内层开始计算,a[0] == 1,从而计算a[1],而a[1] == 2,以此类推,得出最后的值为a[3],即 4。


🧡例题3🧡
#include <stdio.h>
int main() {
    return 0;
}

【运行结果】
【结果答疑】这个例子就是给大家看一下圆括号的,大家看到了吗?没错!main()是个函数,后面的括号里面跟的是参数列表,然而参数列表为空,就变成这个样子了。


🧡例题4🧡
#include <stdio.h>
int a[5] = {5, 4, 3, 2, 1};
int main() {
    printf("%d\n", (a)[2] );
    return 0;
}

【运行结果】3
【结果答疑】这个例子展示了()[]的组合应用,这里的()可有可无。


🧡例题5🧡
#include <stdio.h>
struct A {
    int a;
}a;
int main() {
    a.a = 5;
    printf("%d\n", a.a );
    return 0;
}

【运行结果】5
【结果答疑】这个例子体现了结构体的应用,并且我们可以通过.获取到结构体的成员变量。


🧡例题6🧡
#include <stdio.h>
struct B {
    int c;
};
struct A {
    struct B b;
}a;
int main() {
    a.b.c = 5;
    printf("%d\n", a.b.c );
    return 0;
}

【运行结果】5
【结果答疑】这个例子体现了结构体的嵌套,我们可以通过.获取到结构体的成员变量,成员变量是一个结构体,所以可以继续通过.获取它的成员变量,也间接了解了.运算符的结合性是从左往右的。


🧡例题7🧡
#include <stdio.h>
struct A {
    int b;
}a[10];
int main() {
    a[0].b = 5;
    printf("%d\n", a[0].b);
    return 0;
}

【运行结果】5
【结果答疑】这个例子体现了结构体数组的应用,即当数组元素是一个结构体时,我们如何去访问它的成员变量。体现了[].的混合应用:优先级相同,结合性从左到右。


🧡例题8🧡
#include <stdio.h>
struct A {
    int b;
}a;
struct A *pa;
int main() {
    a.b = 9; 
    pa = &a;
    printf("%d\n", pa->b);
    return 0;
}

【运行结果】9
【结果答疑】这个例子体现了指针的的应用,->左边的操作数是指针本针,右边的就指针指向对象的成员变量。有关于指针的内容,在后面的例题中会反复提到,现在只需要知道pa->b是取成员变量就行了。


🧡例题9🧡
#include <stdio.h>
int a = 3, b = 4;
int main() {
    printf("%d\n", a++b);
    return 0;
}

【运行结果】编译报错!
【结果答疑】编译报错的原因就是编译器不知道如何解析a++b这个语句,但是我们只需要在两个加号之间加个空格,结果就截然不同了,看【例题10】。


🧡例题10🧡
#include <stdio.h>
int a = 3, b = 4;
int main() {
    printf("%d\n", a+ +b);
    return 0;
}

【运行结果】7
【结果答疑】原因就是因为加了空格以后,他就把+理解成b的前缀了,也就是+bb等价,这样一来。


🧡例题11🧡
#include <stdio.h>
int a[3] = {0, 1, 2};
int main() {
    printf("%d\n", -a[2]);
    return 0;
}

【运行结果】-2
【结果答疑】这个例子体现了[]的优先级高于-,即-a[2]等价于-(a[2])


🧡例题12🧡
#include <stdio.h>
struct A {
    int a;
}a;
int main() {
    a.a = 5;
    printf("%d\n", - a.a );
    return 0;
}

【运行结果】-5
【结果答疑】这个例子体现了.的优先级高于-


🧡例题13🧡
#include <stdio.h>
double a[3] = {1.1, 2.2, 3.3};
int main() {
    printf("%d\n", (int)a[2] );
    return 0;
}

【运行结果】3
【结果答疑】这个例子体现了[]的优先级高于(type)


🧡例题14🧡
#include <stdio.h>
struct A {
    double a;
}a;
int main() {
    a.a = 5.6;
    printf("%d\n", (int)a.a );
    return 0;
}

【运行结果】5
【结果答疑】这个例子体现了.的优先级高于(type)


🧡例题15🧡
#include <stdio.h>
struct A {
    double a;
}a;
int main() {
    a.a = 5.6;
    printf("%d\n", (int)a.a );
    return 0;
}

【运行结果】5
【结果答疑】这个例子体现了.的优先级高于(type)


🧡例题16🧡
#include <stdio.h>
int a[5] = {1, 2, 3, 4, 5};
int main() {
    printf("%d\n", ++a[2] );
    return 0;
}

【运行结果】4
【结果答疑】这个例子体现了[]的优先级高于++,且++作为前缀运算符时,返回的是自增后的结果。


🧡例题17🧡
#include <stdio.h>
int a[5] = {1, 2, 3, 4, 5};
int main() {
    printf("%d\n", ++a[2]++ );
    return 0;
}

【运行结果】编译错误!
【结果答疑】这个例子说明 ++ 这个运算符只能作用在变量上,不能作用在表达式上。


🧡例题18🧡
#include <stdio.h>
int a[4] = {1, 2, 3, 4};
int main() {
    printf("%d\n", a[2]++ );
    return 0;
}

【运行结果】3
【结果答疑】这个例子体现了[]的优先级高于++,且++作为后缀运算符时,返回的是自增前的结果。


🧡例题19🧡
#include <stdio.h>
int a = 0;
int main() {
    printf("%d\n", !++a );
    return 0;
}

【运行结果】0
【结果答疑】这个例子是要告诉读者,++!都是右结合的,即++运算会在!运算之前,所以相当于!1,所以值为0


🧡例题20🧡
#include <stdio.h>
int a = 0;
int main() {
    printf("%d\n", ~~~~~~a );
    return 0;
}

【运行结果】0
【结果答疑】这个例子展示了按位取反的右结合性,总共取反六次,相当于没有取反。表达式的效果是等价于~(~(~(~(~(~a)))))的。


🧡例题21🧡
#include <stdio.h>
int a = 0;
int main() {
    printf("%d\n", &a );
    return 0;
}

【运行结果】未知整数
【结果答疑】这个例子告诉我们&a得到的是a这个变量的地址,而非其本身的值。


🧡例题22🧡
#include <stdio.h>
int a = 6;
int main() {
    printf("%d\n", *&a );
    return 0;
}

【运行结果】6
【结果答疑】这个例子的含义是为了说明*&是互逆的关系:&是取变量的地址,*是根据变量地址取值,而地址又叫指针,所以*又叫解指针,也可以叫解引用。


🧡例题23🧡
#include <stdio.h>
int a[2] = {3, 4};
int main() {
    printf("%d %d\n", &a[1], (&a)[1] );
    return 0;
}

【运行结果】两个不同的值
【结果答疑】得到的是两个不同的值,为什么呢?继续来看【例题24】。


🧡例题24🧡
#include <stdio.h>
int a[2] = {3, 4};
int main() {
    printf("%d %d\n", &a[1], &(a[1]) );
    return 0;
}

【运行结果】两个相同的值
【结果答疑】得到的是两个相同的值,这里简单解释一下,就是因为[]的优先级比&高,&a[1]相当于取数组的第1个元素后再取地址,相当于基地址a加四个字节(int的大小是4个字节);但是(&a)[1]相当于先取地址变成了指针,指针在目前64位机器上是8个字节的,再进行一次下标运算,相当于基地址a加8个字节,完美!(不懂的话我将来会在 光天化日写C语言 (50) - 指针初探 里面详细讲解,尽请关注 🌞《光天化日学C语言》🌞


🧡例题25🧡
#include <stdio.h>
struct A {
    int *b;
}a;
struct A *pa;
int x = 996; 
int main() {
    a.b = &x;
    printf("%d\n", *a.b);
    return 0;
}

【运行结果】996
【结果答疑】这个例子体现了指针的的应用,并且说明了.的优先级高于*。其中a.b是一个指针,指向的是x,经过*解引用以后,得到了x变量的值,即996,有点伤感……


🧡例题26🧡
#include <stdio.h>
struct A {
    int *b;
}a;
struct A *pa;
int x = 996; 
int main() {
    a.b = &x;
    printf("%d\n", *(a.b));
    return 0;
}

【运行结果】996
【结果答疑】这个例子的运算过程和【例题25】是等价的。


🧡例题27🧡
#include <stdio.h>
int a[2] = {3, 4};
int main() {
    printf("%d\n", **a );
    return 0;
}

【运行结果】编译错误
【结果答疑】这个例子是想要说明*只能对指针类型解引用,直接来看【例题28】再来进行详细解释。


🧡例题28🧡
#include <stdio.h>
int a[2] = {3, 4};
int main() {
    printf("%d\n", *a );
    return 0;
}

【运行结果】3
【结果答疑】这个例子是想要说明数组的首地址,就是指针指向的位置,所以直接解引用拿到的就是数组的第一个元素。


🧡例题29🧡
#include <stdio.h>
int a[2] = {3, 4};
int main() {
    printf("%p %p\n", a, &*a );
    return 0;
}

【运行结果】两个相同的值
【结果答疑】这个例子是进一步说明数组的首地址,就是指针指向的位置,a代表数组首地址,对首地址解引用,得到的就是a[0],然后再取地址&,得到的就是数组a的首地址了(刚接触指针的话,这块可能比较绕,建议自己写一下代码看看效果)。


🧡例题30🧡
#include <stdio.h>
int a[2] = {99, 6};
int *pa[1];
int main() {
    pa[0] = a;
    printf("%d\n", *pa[0] );
    return 0;
}

【运行结果】99
【结果答疑】这个例子表明[]的优先级高于解引用*


🧡例题31🧡
#include <stdio.h>
int a[2] = {10, 7};
int main() {
    printf("%d\n", a[0] * a[1] );
    return 0;
}

【运行结果】70
【结果答疑】这个例子表明[]的优先级高于乘法*


🧡例题32🧡
#include <stdio.h>
int a[2] = {10, 5};
int main() {
    printf("%d\n", a[0] / a[1] );
    return 0;
}

【运行结果】2
【结果答疑】这个例子表明[]的优先级高于除法/


🧡例题33🧡
#include <stdio.h>
int a[2] = {10, 3};
int main() {
    printf("%d\n", a[0] / a[1] );
    return 0;
}

【运行结果】3
【结果答疑】整数间的除法是取下整。


🧡例题34🧡
#include <stdio.h>
int a[2] = {10, 0};
int main() {
    printf("%d\n", a[0] % a[1] );
    return 0;
}

【运行结果】异常
【结果答疑】会产生除零错误,因为取模时除数不能为零。


🧡例题35🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 + 1 % 2);
    return 0;
}

【运行结果】2
【结果答疑】取模运算符%的优先级高于加法运算符+


🧡例题36🧡
#include <stdio.h>
int a = 1;
int main() {
    printf("%d\n", a++ + ++a);
    return 0;
}

【运行结果】4
【结果答疑】千万别写出这种代码,因为不同编译器可能产生不同的编译结果。


🧡例题37🧡
#include <stdio.h>
int a = 1;
int main() {
    printf("%d\n", a++ + ++a);
    return 0;
}

【运行结果】4
【结果答疑】千万别写出这种代码,因为不同编译器可能产生不同的编译结果。


🧡例题38🧡
#include <stdio.h>
int a = 7;
int *fun(int *p) {
    return p;
}
int main() {
    printf("%d\n", *fun(&a));
    return 0;
}

【运行结果】7
【结果答疑】这段代码将全局变量的地址作为函数传参传到函数中,然后再返回出来,再解引用得到全局变量的值。这里想说明的是int *fun(...)是一个指针函数,即返回int *的函数,所以它等价于int *(fun(...)),因为()的优先级高于指针运算符*


🧡例题39🧡
#include <stdio.h>
int a = 5;
int main() {
    printf("%p %p\n", &a, &a + 1);
    return 0;
}

【运行结果】两个相差4的地址
【结果答疑】这个例子说明几个问题:首先,指针是可以进行加法运算的,并且不是作为整数来进行加法运算,指针的加1,相当于按照指针指向的类型偏移对应的单位,且取地址&的优先级高于加号+


🧡例题40🧡
#include <stdio.h>
int a = 5;
int main() {
    printf("%p %p\n", &a, &a - 1);
    return 0;
}

【运行结果】两个相差4的地址
【结果答疑】这个例子说明几个问题:首先,指针是可以进行减法运算的,并且不是作为整数来进行减法运算,指针的减1,相当于按照指针指向的类型偏移对应的单位,且取地址&的优先级高于加号-


🧡例题41🧡
#include <stdio.h>

int main() {
    printf("%d\n", 1 << 3 - 1);
    return 0;
}

【运行结果】4
【结果答疑】1 << 3 - 1等价于1 << (3 - 1),因为算术运算符的优先级高于移位运算符。


🧡例题42🧡
#include <stdio.h>

int main() {
    printf("%d\n", 1 << 3 + 1);
    return 0;
}

【运行结果】16
【结果答疑】1 << 3 + 1等价于1 << (3 + 1),因为算术运算符的优先级高于移位运算符。


🧡例题43🧡
#include <stdio.h>
int a[5] = {9, 8, 7, 6, 5};
int main() {
    int *p = a;
    printf("%d\n", *p++);
    return 0;
}

【运行结果】9
【结果答疑】这个例子中,*++的优先级是相同的,但是无奈这两个的结合性是从右到左的,所以它等价于*(p++),而且p++表达式的值等于p。所以最后解引用的还是数组的第一个元素。


🧡例题44🧡
#include <stdio.h>
int a[5] = {9, 8, 7, 6, 5};
int main() {
    int *p = a;
    printf("%d\n", *++p);
    return 0;
}

【运行结果】8
【结果答疑】这个例子是用来类比【例题43】的,它输出则是数组的第2个元素的值。


🧡例题45🧡
#include <stdio.h>
int a[5] = {9, 8, 7, 6, 5};
int main() {
    int *p = a;
    printf("%d\n", *p<<1);
    return 0;
}

【运行结果】18
【结果答疑】这个例子中,解引用*的优先级高于左移运算符<<


🧡例题46🧡
#include <stdio.h>
int a[5] = {9, 8, 7, 6, 5};
int main() {
    int *p = a;
    printf("%d\n", *p>>1);
    return 0;
}

【运行结果】4
【结果答疑】这个例子中,解引用*的优先级高于右移运算符>>


🧡例题47🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1<<1>>1<<1>>1);
    return 0;
}

【运行结果】1
【结果答疑】这个例子中,左移运算符<<和左移运算符>>的优先级优先级相同,结合性从左到右。


🧡例题48🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1<<1.6);
    return 0;
}

【运行结果】编译错误
【结果答疑】这个例子是为了说明<<右边的操作数一定要是整数。


🧡例题49🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1.6<<1);
    return 0;
}

【运行结果】编译错误
【结果答疑】这个例子是为了说明<<左边的操作数一定要是整数。


🧡例题50🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 > 2);
    printf("%d\n", 1 < 2);
    return 0;
}

【运行结果】0[换行]1
【结果答疑】这个例子告诉我们关系运算符的运算结果,如果为真返回1,否则返回0。


🧡例题51🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 < 1 << 2);
    return 0;
}

【运行结果】1
【结果答疑】左移运算符<<的优先级高于关系运算符<


🧡例题52🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 > 2 > -1);
    return 0;
}

【运行结果】1
【结果答疑】由于1 > 2的结果为0,所以1 > 2 > -1等价于0 > -1,显然是成立的,所以输出的结果为:1


🧡例题53🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 < 2 > 1);
    return 0;
}

【运行结果】0
【结果答疑】由于1 < 2的结果为1,所以1 < 2 > 1等价于1 > 1,显然是不成立的,所以输出的结果为:0


🧡例题54🧡
#include <stdio.h>
int main() {
    printf("%d\n", 3 > 2 > 1);
    return 0;
}

【运行结果】0
【结果答疑】由于3 > 2的结果为1,所以3 > 2 > 1等价于1 > 1,显然是不成立的,所以输出的结果为:0


🧡例题55🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 < 2 == 1);
    return 0;
}

【运行结果】1
【结果答疑】我们可以做出两种假设:
  假设1:==优先级低于<1 < 2优先计算,则表达式等价于1 == 1,成立,输出1
  假设2:==优先级高于<2 == 1优先计算,则表达式等价于1 < 0,不成立,输出0
实际上,这段代码的结果为:1,即==的优先级低于<


🧡例题56🧡
#include <stdio.h>
int main() {
    printf("%d\n", 1 < 2 != 1);
    return 0;
}

【运行结果】0
【结果答疑】类似【例题55】。


🧡例题57🧡
#include <stdio.h>
int main() {
    int a; 
    printf("%d\n", a = 0);
    return 0;
}

【运行结果】0
【结果答疑】这里其实是想进行a == 0的关系判定,结果=少写了一个,所以结果变成了赋值号=右边表达式的值。


🧡例题58🧡
#include <stdio.h>
int main() {
    printf("%d\n", 5 <= 6);
    return 0;
}

【运行结果】1
【结果答疑】当然是成立的啦。


🧡例题59🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0110;
    printf("%d\n", a & b );
    return 0;
}

【运行结果】2
【结果答疑】这个例子展示了位与的基本运算。


🧡例题60🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0110;
    printf("%d\n", a & b == 2);
    return 0;
}

【运行结果】0
【结果答疑】延续【例题59】继续看,之前a & b输出的是2,那为什么加上等于==判定后,输出结果反而变成0了呢?原因是因为==的优先级高于位与&,所以相当于进行了a & 0的操作,结果自然就是0了。


🧡例题61🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    printf("%d\n", a & 1 << 3);
    return 0;
}

【运行结果】8
【结果答疑】这个例子体现了左移运算符<<优先级高于位与&a & 1 << 3相当于a & (1 << 3)


🧡例题62🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    printf("%d\n", a | 1 << 2);
    return 0;
}

【运行结果】14
【结果答疑】这个例子体现了左移运算符优先级高于位或。


🧡例题63🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    printf("%d\n", a ^ 1 << 2 == 4);
    return 0;
}

【运行结果】11
【结果答疑】这个例子中运算符优先级:<<高于==高于^。好了,当到达这种复杂情况的时候,你就应该想到要加括号了。


🧡例题64🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    printf("%d\n", a ^ ( (1 << 2) == 4 ) );
    return 0;
}

【运行结果】11
【结果答疑】和【例题63】等价。


🧡例题65🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1000;
    printf("%d\n", a ^ b & c );
    return 0;
}

【运行结果】10
【结果答疑】这个例子表明了位与运算符&高于异或运算符^


🧡例题66🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1001;
    printf("%d\n", a | b & c );
    return 0;
}

【运行结果】11
【结果答疑】这个例子表明了位与运算符&高于位或运算符 | 。


🧡例题67🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1001;
    printf("%d\n", a | b ^ c );
    return 0;
}

【运行结果】14
【结果答疑】这个例子表明了异或运算符^高于位或运算符 | 。


🧡例题68🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1001;
    printf("%d\n", a | b ^ c );
    return 0;
}

【运行结果】14
【结果答疑】这个例子表明了异或运算符^高于位或运算符 | 。


🧡例题69🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1001;
    printf("%d\n", a | b | c );
    return 0;
}

【运行结果】15
【结果答疑】位或运算符 | 的结合性是从左到右的,不过如果全是 | ,其实它是满足结合律的,所以顺序不太重要。


🧡例题70🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1001;
    printf("%d\n", a & b & c );
    return 0;
}

【运行结果】0
【结果答疑】位与运算符&的结合性是从左到右的,不过如果全是&,其实它是满足结合律的,所以顺序不太重要。


🧡例题71🧡
#include <stdio.h>
int main() {
    int a = 0b1010;
    int b = 0b0101;
    int c = 0b1001;
    printf("%d\n", a ^ b ^ c );
    return 0;
}

【运行结果】6
【结果答疑】异或运算符^的结合性是从左到右的,不过如果全是^,其实它是满足结合律的,所以顺序不太重要。


🧡例题72🧡
#include <stdio.h>
int main() {
    int x = 64;
    printf("%d\n", (x & x - 1) == 0 );
    return 0;
}

【运行结果】1
【结果答疑】这个例子是用来判断一个数是不是2的幂的。由于减号-的优先级高于&,所以x & x - 1等价于x & (x - 1),但是==的优先级高于&,所以(x & x - 1)中的括号不能省。当然也可以写成!(x & x - 1)


🧡例题73🧡
#include <stdio.h>
int main() {
    int a = 0b10000; 
    int x = 0b01011; 
    printf("%d\n", (x | a) - a ); 
    return 0;
}

【运行结果】11
【结果答疑】这个例子是用来消除x的第5位的,首先利用位或运算符 | 将第5位强制变成1,然后消除掉这个1。由于减法运算符-优先级高于位或运算符 | ,所以需要加上括号。


🧡例题74🧡
#include <stdio.h>
int main() { 
    int x = 0b010000; 
    printf("%d\n", x | x - 1 ); 
    return 0;
}

【运行结果】31
【结果答疑】这个例子是是将低位连续的零变成一,但是一般这样的写法会报警告,因为编译程序并不知道你的诉求,到底是想先计算 | 还是先计算 -,由于这个问题我们实际要计算的是x | (x - 1),并且减法运算符-优先级高于位或运算符 | ,所以括号是可以省略的。


🧡例题75🧡
#include <stdio.h>
int main() { 
    printf("%d\n", 1 && 2 && 3 ); 
    return 0;
}

【运行结果】1
【结果答疑】这个例子是展示了逻辑与&&的用法。


🧡例题76🧡
#include <stdio.h>
int main() {
    int a = 0;
    printf("%d\n", ++a && a-1 ); 
    return 0;
}

【运行结果】0
【结果答疑】这个例子是展示逻辑与运算符&&的结合性是从左到右的,先计算++a,再计算a-1,结果为1 && 00


🧡例题77🧡
#include <stdio.h>
int main() {
    int a = 0;
    printf("%d\n", a-1 && ++a ); 
    return 0;
}

【运行结果】1
【结果答疑】这个例子是展示逻辑与运算符&&的结合性是从左到右的,先计算a-1,再计算++a,结果为-1 && 11


🧡例题78🧡
#include <stdio.h>
int main() {
    int a = 1;
    printf("%d\n", a-1 || --a ); 
    return 0;
}

【运行结果】0
【结果答疑】这个例子是展示逻辑或运算符&&的结合性是从左到右的,先计算a-1,结果为0,再计算--a,结果为0。所以逻辑或的结果为0


🧡例题79🧡
#include <stdio.h>
int main() {
    int a = 1;
    printf("%d\n", --a || a-1  ); 
    return 0;
}

【运行结果】1
【结果答疑】这个例子是展示逻辑或运算符&&的结合性是从左到右的,先计算--a,结果为0,再计算a-1,结果为-1。所以逻辑或的结果为1


🧡例题80🧡
#include <stdio.h>
int main() {
    int a = 1;
    --a && --a;
    printf("%d\n", a); 
    return 0;
}

【运行结果】0
【结果答疑】这个例子是展示逻辑或运算符&&从左往右计算过程中,一旦遇到 0 就不再进行运算了,所以--a实际上只执行了一次。


🧡例题81🧡
#include <stdio.h>
int main() {
    int a = 1;
    --a && --a;
    printf("%d\n", a); 
    return 0;
}

【运行结果】0
【结果答疑】这个例子是展示逻辑与运算符&&从左往右计算过程中,一旦遇到 0 就不再进行运算了,所以--a实际上只执行了一次。


🧡例题82🧡
#include <stdio.h>
int main() {
    int a = 0;
    --a || --a;
    printf("%d\n", a); 
    return 0;
}

【运行结果】1
【结果答疑】这个例子是展示逻辑或运算符从左往右计算过程中,一旦遇到 1 就不再进行运算了,所以--a实际上只执行了一次。


🧡例题83🧡
#include <stdio.h>
int main() {
    int a = 1, b = 1;
    printf("%d\n", a || a && b ); 
    return 0;
}

【运行结果】1
【结果答疑】这个例子是表示&&的优先级高于 || 。


🧡例题84🧡
#include <stdio.h>
int main() {
    int a, b, c;
    a = b = c = 6;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】6
【结果答疑】这个例子是容易得出a b c的值均为6,但是却很难看出赋值运算符的结合性,实际上a = b = c = 6等价于a = (b = (c = 6))。 因为赋值运算符是右结合的,并且赋值运算符的值等于赋值运算符=右边表达式的值。


🧡例题85🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a += b += c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】6
【结果答疑】这个例子是比较容易看懂,基本知道a的值等于a b c三个变量的和,所以值为6


🧡例题86🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a -= b -= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】2
【结果答疑】由于赋值运算符的结合性是从右到左的,所以a -= b -= c的计算方式等价于a = (a - (b - c)),值为 2


🧡例题87🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a *= b *= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】6
【结果答疑】a *= b *= c的计算方式等价于a = (a * (b * c))


🧡例题88🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a /= b /= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】异常
【结果答疑】a /= b /= c的计算方式等价于a = (a / (b / c)),所以除数b / c等于0,所以导致除法异常。


🧡例题89🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a %= b %= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】1
【结果答疑】a %= b %= c的计算方式等价于a = (a % (b % c)),结果为1


🧡例题90🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a <<= b <<= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】65536
【结果答疑】a <<= b <<= c的计算方式等价于a = (a << (b << c)),结果为1 << 16


🧡例题91🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a >>= b >>= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】1
【结果答疑】a >>= b >>= c的计算方式等价于a = (a >> (b >> c)),结果为1 >> 0


🧡例题92🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a &= b &= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】0
【结果答疑】a &= b &= c的计算方式等价于a = (a & (b & c)),由于&满足结合律,结果等价于a = (a & b & c)


🧡例题93🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a |= b |= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】3
【结果答疑】同【例题92】,位或运算符同样满足结合律。


🧡例题94🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    a ^= b ^= c;
    printf("%d\n", a ); 
    return 0;
}

【运行结果】0
【结果答疑】a ^= b ^= c的计算方式等价于a = (a ^ (b ^ c)),由于^满足结合律,结果等价于a = (a ^ b ^ c)


🧡例题95🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2;
    printf("%d\n", a > b ? a + b : a - b ); 
    return 0;
}

【运行结果】-1
【结果答疑】条件运算符的优先级较低,低于关系运算符和算术运算符,所以a > b ? a + b : a - b等价于1 > 2 ? 3 : -1


🧡例题96🧡
#include <stdio.h>
int main() {
    int a = 1, b = 2, c = 3;
    printf("%d\n", a < b ? b > c ? 9 : 7 : a - b ); 
    return 0;
}

【运行结果】7
【结果答疑】这个例子主要是用来解释条件运算符的结合性是从右到左的,等价于a < b ? (b > c ? 9 : 7) : a - b


🧡例题97🧡
#include <stdio.h>
int main() {
    int a = 2, b = 3;
    printf("%d\n", a <<= a < b ? a + b : a - b ); 
    return 0;
}

【运行结果】64
【结果答疑】这个例子主要是说明赋值运算符的优先级低于条件运算符。即a <<= a < b ? a + b : a - b等价于a <<= (a < b ? a + b : a - b)


🧡例题98🧡
#include <stdio.h>
int main() {
    int a = 2, b = 3;
    printf("%d\n", a *= a < b ? a + b : a - b ); 
    return 0;
}

【运行结果】10
【结果答疑】这个例子主要是说明赋值运算符的优先级低于条件运算符。即a *= a < b ? a + b : a - b等价于a *= (a < b ? a + b : a - b)


🧡例题99🧡
#include <stdio.h>
int main() {
    int a = 2, b = 3;
    printf("%d\n", a += a < b ? a + b : a - b ); 
    return 0;
}

【运行结果】7
【结果答疑】这个例子主要是说明赋值运算符的优先级低于条件运算符。即a += a < b ? a + b : a - b等价于a += (a < b ? a + b : a - b)


🧡例题100🧡
#include <stdio.h>
int main() {
    int tmp, a = 2, b = 3;
    tmp = a, a = b, b = tmp;
    printf("%d\n", a << b ); 
    return 0;
}

【运行结果】12
【结果答疑】这个例子主要是说明逗号运算符的优先级是最低的,可以放心使用。

🙉饭不食,水不饮,题必须刷🙉

还不会C语言,和我一起打卡!
🌞《光天化日学C语言》🌞

LeetCode 太难?上简单题!
🧡《C语言入门100例》🧡

LeetCode 太简单?大神盘他!
🌌《夜深人静写算法》🌌

在这里插入图片描述

  • 122
    点赞
  • 569
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 385
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 385
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值