当前位置 博文首页 > 英雄哪里出来:??三万字《C语言运算符优先级面试错题100例》??

    英雄哪里出来:??三万字《C语言运算符优先级面试错题100例》??

    作者:[db:作者] 时间:2021-08-18 18:53

    • 建议先阅读基础教学:??《十万字C语言动漫教程》??

    在这里插入图片描述

    一、前言

    ??运算符优先级一直是让人头疼的东西,趁着 字节取消大小周 的势头来临,通宵整理了一个思维导图出来,希望对你有所帮助。这篇文章,我会仔细分析这张思维导图。
    ??所有的 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(