• 浅识C语言中那些操作符(保证足够详细)


            浅识C语言中那些操作符!(保证足够详细)

    在C语言中,有着众多的操作符,如果不能正确认识,那么在书写C语言代码时候,将会遇到这样那样的错误,甚至对于自己写的代码,都不知道bug在哪?更何况,去找bug呢??

    因此,我们需要正确的去认识,并且知道每一个C语言操作符所代表的具体含义是什么!这样我们看待代码时候,才不会两眼抓瞎!

    下面,笔者将带领大家认识一下,笔者所认识,及所感悟到操作符!!

    1.算数操作符:

             +   -  *    /  %

    在这里面,算术操作符,算是大家较为了解的操作符,毕竟每一个代码中,或多或少都会用到算术操作符!

    但是我们运用时候,还要注意一下几点!

    (1).除了%取除操作符之外,其他几个操作符,都可以应用于整数和浮点数

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

    (3).%取余操作符的两个操作数必须是整数!(很重要)

     笔者亲测,这样将会进行报错!所以不能有这样的写法!

    (4)./除法中,要想得到小数(浮点数),则必须保证在除数和被除数之间必须有一个小数(浮点数)

    (5),我们还需要注意,加减乘除取余运算符之间的优先级!

    2.移位操作符

    《  左移位操作符    ;     》  右移位操作符

    在这里,我们需要注意的是,移位操作符的操作数,只能是整数(小数,负数都不行),移位负数将没有意义

    移位操作符:移动的是二进制位!

    下面,我们需要浅浅介绍一下:二进制如何去表达??

    如数值15:

    在我们计算机中平常输入加使用的都是十进制形式! 

    在十进制中:15=1*10的一次幂+5*10的0次幂

    在二进制中:15=1*2的3次幂+1*2的2次幂+1*2的一次幂+1*2的0次幂

    在八进制中:15=1*8的1次幂+7*8的0次幂

    至于其他的进制,由于篇幅原因,笔者将不再进行详细解答!

    需要注意的是:10进制的表示为:0~9;

                              8进制的表示为0~7;

                               2进制的表示为0,1;

    在二进制中:15=1*2的3次幂+1*2的2次幂+1*2的一次幂+1*2的0次幂

    因此15的二进制表示为:00000000000000000000000000001111(一共32位)

    原因为:15 是个整数,在C语言中可以存放在int 类型的变量中,而int类型的变量占4个字节(32个比特位)

    上面我们已经了解到了进制的表达形式!但是,整型在计算机中的二进制的表达形式.............

    整型的二进制的表示有三种:原码,反码,补码!

    原码:直接根据数值写出的二进制序列就是原码

    反码:原码的符号位不变,其余位按位取反就是反码

    补码:反码+1就是补码

    符号位:

                       开头的第一位就是符号位!

                       符号位位0:表示正数

                       符号位位1:表示负数

    因此,对于15来说:(正数的原码,反码,补码相同)

    00000000000000000000000000001111          15的原码

    00000000000000000000000000001111           15的反码

    00000000000000000000000000001111         15的补码

    对于-15来说:(注意符号位的改变)

    10000000000000000000000000001111            -15的原码

    111111111111111111111111111111110000           -15的反码(原码的符号位不变,其余位按位取反就是反码)

    111111111111111111111111111111110001           -15的补码(反码+1)

    移位操作符:移动的是存储在内存中的补码!

    当a=4时:

    1. #include
    2. int main()
    3. {
    4. int a = 4;
    5. //a的补码00000000000000000000000000000100
    6. int b = a << 1;
    7. //把a向左移动1位
    8. printf("a=%d b=%d\n", a, b);
    9. return 0;
    10. }

    在这里,我们来看一下代码的运转结果:

     对于这个结果:我们发现:移位运算符不改变原数值的大小!

    00000000000000000000000000000100               4的(原码,反码,补码)

    在移位运算符中,移动的是存储在内存中的补码!

     因此,我们可以看出来,左移操作符规则:左边丢弃,右边补0;

    当a=-4时候:

    1. #include
    2. int main()
    3. {
    4. int a = -4;
    5. //a的原码10000000000000000000000000000100
    6. int b = a << 1;
    7. //把a向左移动1位
    8. printf("a=%d b=%d\n", a, b);
    9. return 0;
    10. }

    我们需要知道-4的原码,反码,补码

    因此:

    10000000000000000000000000000100           -4的原码

    111111111111111111111111111111111011            -4的反码

    111111111111111111111111111111111100             -4的补码

    然后在根据刚才序列进行左移一位,得到的结果就是:

    111111111111111111111111111111111000               补码

    111111111111111111111111111111110111              反码(补码-1)

    10000000000000000000000000001000              原码(反码符号位不变,其余位按位取反)

    因此该数值为-8

    因此,由上面两个代码,我们可以看出:左移操作符有乘2的效果!

    注意,补码在移动过程中,如果将符号位移丢了,:那么,移丢就移丢,后面还能补回来!

    右移操作符  《

    当a=-4时候:

    1. #include
    2. int main()
    3. {
    4. int a = -4;
    5. //10000000000000000000000000000100 - 4的原码
    6. //111111111111111111111111111111111011 - 4的反码
    7. //111111111111111111111111111111111100 - 4的补码
    8. int b = a >> 1;
    9. //把a向右移动1位
    10. printf("a=%d b=%d\n", a, b);
    11. return 0;
    12. }

    下面我们就a=-4来分析右移操作符:

     对于右移操作符:左边空出来的一位:有两种补法!(在C语言中卖淫给出明显的绝对答案,只能根据编译器得来计算答案)

    右移操作符:

                a.逻辑右移:

                              右边丢弃,左边补0;

                b.算术右移:(绝大多数是这样的)

                             右边丢弃,左边补原符号位(正数补0,负数补1)

     对于该运算结果,结合二进制的右移结果,我们可以看出来用了算术右移!

    因此,我们可以看出来,右移操作符有除2的效果!

    3.位操作符(二进制的条件下)

    &  按位与

    |   按位或

    ^   按位异或

    (1).   &   按位与

    下面,笔者来结合此代码来进行分析:

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

    00000000000000000000000000000011          3的补码

    10000000000000000000000000000101         -5的原码

    111111111111111111111111111111111010          -5的反码

    111111111111111111111111111111111011          -5的补码

    因此,对于:

    00000000000000000000000000000011          3的补码

    111111111111111111111111111111111011          -5的补码

    由&  按位与,可以得出:

    00000000000000000000000000000011           补码(原码)

    按位与规则:有0则为0,都1则为1

    则打印结果为c=3

     (2).      |    按位或

    下面,笔者来结合此代码来进行分析(对上面代码进行浅浅改造)

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

    还是在补码上进行操作:

    00000000000000000000000000000011          3的补码

    111111111111111111111111111111111011          -5的补码

    对于   |    按位或  ,可以得出:

    11111111111111111111111111111111011            补码(负数)

    则进补码-1到反码,在到原码的操作,可以得出该数字!

    因此: |     按位或规则为:只要有1则为1,两个为0则为0;

    最后的打印结果为:

     (3)   ^   按位异或

    下面,笔者来结合此代码来进行分析(对上面代码进行浅浅改造)

    1. #include
    2. int main()
    3. {
    4. int a = 3;
    5. int b = -5;
    6. int c = a ^ b;
    7. printf("c=%d\n", c);
    8. return 0;
    9. }

    我们仍然需要3跟-5的补码:

    00000000000000000000000000000011          3的补码

    111111111111111111111111111111111011          -5的补码

    由           ^    按位异或得出:

    111111111111111111111111111111111000          补码(负数)

    则进补码-1到反码,在到原码的操作,可以得出该数字!

    因此   ^  按位异或的运算规则为:

    相同为0,不同为1;

    因此,该代码的运算结果为:

     另外需要注意的是:

    ^   按位异或:

    1,相同的数字按位异或结果为0;即3^3=0;

    2,按位异或支持交换律;即3^5^6等于6^3^5;

    4.赋值运算符

    =

    赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的数值,也就是你可以给自己重新赋值

    int  weight=120;

    weight=89;//不满意就赋值

    下面介绍连续赋值

    1. #include
    2. int mian()
    3. {
    4. int a = 10;
    5. int b = 0;
    6. b = a = a + 3;
    7. printf("a=%d b=%d\n", a, b);
    8. return 0;
    9. }

     在这里,b=a=a+3;是连续赋值的结果,最后的打印结果为:a=13,b=13;但是不建议这样去写。程序运转错误以后,没有办法去深入该表达式进行调试!

    5.赋值运算符

    +=            -=          *=          /=                %=           

    >>=              <<=           &=          |=          ^=

    6.单目操作符

    !逻辑反操作符

    -  负值

    +  正值

    &  取地址

    sizeof   求操作符的类型长度(以字节为单位)

    ~    对一个数的二进制按位取反

    --     前置,后置--

    ++  前置,后置++

    *    间接访问操作符(解引用操作符)

    (类型)   强制类型转化

    1.    ! 逻辑反操作符

    笔者将用下面代码来解析:

    1. #include
    2. int main()
    3. {
    4. int flag = 0;
    5. if (!flag)
    6. {
    7. printf("hehe\n");
    8. }
    9. return 0;
    10. }

    在if语句中,用了 !逻辑反操作符,

    运转结果为:打印了hehe

     但是笔者前面定义了flag=0,按照if语句中的,0表示假,是不会进入if语句,直接什么都不进行输出!但是最后的运转结果却是输出了hehe ,因此,!  逻辑反操作有取反的意思

    2.  &   取地址操作符

    &   取地址操作符  常常与      *    间接访问操作符(解引用操作符) 在指针中联用!

    int a=10;

    int *pa=&a;   //在这里int指a的类型,*指pa为指针变量

    1. #include
    2. int main()
    3. {
    4. int a = 10;
    5. int* pa = &a;
    6. printf("%d\n", a);
    7. printf("%d\n", *pa); //由地址找到该数
    8. printf("%d\n", pa); //打印pa的地址
    9. return 0;
    10. }

    代码的运转结果为:

     

    *pa——》解引用操作符,最后得到a的值10;

    pa——》得到a的地址

    3.sizeof 操作数的类型长度(以字节为单位)

    在多处都有涉及!

    1. #include
    2. int main()
    3. {
    4. short s = 10;
    5. int a = 2;
    6. printf("%d\n", sizeof(s = a + 5)); //2
    7. printf("s=%d\n", s); //10
    8. return 0;
    9. }

    借助此代码,笔者提醒大家,sizeof(表达式)   表达式内部不进行计算!

    代码的运行结果为:short类型占2 个字节!在这里s 的值仍然为10;

     注意数组传参时候:

    1. #include
    2. void test1(int arr[])
    3. {
    4. printf("%d\n", sizeof(arr)); //8
    5. }
    6. void test2(char ch[])
    7. {
    8. printf("%d\n", sizeof(ch)); //8
    9. }
    10. int main()
    11. {
    12. int arr[10] = { 0 };
    13. char ch[10] = { 0 };
    14. printf("%d\n", sizeof(arr)); //40
    15. printf("%d\n", sizeof(ch)); //10
    16. test1(arr);
    17. test2(ch);
    18. return 0;
    19. }

    在这里,我们需要注意的是:数组传参时候,传递的是首元素地址 ,占据4个(32位条件下)或者8个字节(64位条件下)

    因此最后的打印结果为:

     之前笔者就这这里栽过,因此需要读者强加注意!

    4.数组名

    数组名是数组首元素地址

    但是有两个列外:

    1.sizeof(数组名),在这里数组名表示的是整个数组,不是首元素地址

    sizeof(数组名)计算的是整个数组的大小,单位是字节

    2.   &数组名,在这里数组名表示的是整个数组,不是首元素地址,

    &数组名,取出的是整数组的地址!

    5.  ~   对一个数的二进制按位取反

    下面笔者将用代码来进行讲解:

    1. #include
    2. int main()
    3. {
    4. int a = 0;
    5. printf("%d\n", ~a);
    6. return 0;
    7. }

    在这楼里,我们仍然需要最大a=0的二进制

    00000000000000000000000000000000       0的补码

    ~      对一个数的二进制进行按位取反(包过符号位)

    11111111111111111111111111111111           补码(负数)

    11111111111111111111111111111110         反码(补码-1)

    1000000000000000000000000001            原码(反码符号位不变,其余位按位取反)

    即得到的结果为-1;

     7,逻辑操作符

    &&   逻辑与操作符

    ||      逻辑或操作符

    下面笔者将用代码来进行讲解:

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

    在该段代码中,用了前后置++运算符,因此我们需要注意:++i;先++,后输出,i++,先使用,后++;

    &&   逻辑与操作符     只要前面有0,就不进行后面的运算

    ||      逻辑或操作符      只要前面有1,后面也就不用计算

     对于a++先使用后++,因此,a=0,然后在进行后面.........;但是:&&   逻辑与操作符     只要前面有0,就不进行后面的运算,因此,后面的b,c,d,都不进行运算,然后a在++,然后输出a=1;

    8.条件操作符(唯一一个三目运算符)

    exp1?exp2:exp3

    a>5?3:8

    exp1用来判断条件是否成立,成立则用exp2,否则用exp3

    9.逗号表达式

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

    逗号表达式从左到右依次执行(将前面的结果赋值给后面的字母相同的表达式),表达式的结果为最后一共表达式的结果;

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

    在int c = (a > b, a = b + 10, a, b = a + 1);,我们可以看出来最后c的结果等于最后一个表达式b=a+1的结果!从前面依次计算表达式,可以得出a=12,b=13

    运算结果为:

     

  • 相关阅读:
    一文搞懂漏洞严重程度分析
    Linux传统跨进程通信原理
    Linux常用命令
    【科普向】Jmeter 如何测试接口保姆式教程
    刷刷笔试题--贪心算法
    【OpenCV】车辆识别 目标检测 级联分类器 C++ 案例实现
    功能测试【测试用例模板、Bug模板、手机App测试】
    Spring(JavaEE进阶系列1)
    Minio学习
    LCD简介
  • 原文地址:https://blog.csdn.net/weixin_64308540/article/details/126093508