C语言-运算符与表达式


1.表达式 

    什么是表达式? 
        表达式就是能够表达某种意思的式子 
            a+b     //把a和b的值 相加

    在C语言中 表达式一般是指 运算符连接操作数的式子  
        a+b  2+3  5   100    ...  a=b+c   (单独的一个数也可以看做成一个表达式)

        注意: 任何的表达式都是有一个确定的值的


2.运算符 

    我们用来进行运算的某种符号
        比如: + - * / .... 

        几目运算符:
            表示该运算符需要连接多少个操作数 

            单目运算符: 表示该运算符需要连接1个操作数, 比如: ++ , --, ! ....
            双目运算符: 表示该运算符需要连接2个操作数, 比如: + , - , * , / ..... 
            三目运算符: 表示该运算符需要连接3个操作数, 比如:  ?: (条件运算符)  

        结合性: 
            代表运算时的优先顺序 

            例子: 
                + 结合性: 从左至右 

                    a + b 
                    (1+2) + (3+4) 
                    这个表达式时 先算a,再算b 
                所以 在C语言中, a+b 和 b+a 是不同的含义 


    1)算术运算符 
        进行算术运算的运算符 

            单目运算符: ++ , -- 

            双目运算符: + , - , * , / , % 
                结合性: 从左至右 

        (1) / 取整 
            整数除以整数 其结果还是整数, 如果要变成小数,那么在分子乘以1.0即可  

                5/2     -->  2 
                1.0*5/2 -->  2.5 

            =================================
                隐式类型转换: 高精度的数据和低精度的数据进行运算时,结果会自动转换成高精度的 
                    比如: 
                        int  double  ==>  double 
                        int  short   ==>  int 
                        无符号 有符号 ==>  无符号 
                        char  short  ==>  int 
                        char  char  ==>   int 

                    例子: 
                        char a = '0';
                        char b = 1;
                        printf("%d\n", a+b );   // 49   

                往高精度转换(在64bits操作系统下)
                    char --> short  --> int  --> unsigned int -->  long ---> unsigned long  
                    --> long long (8个字节)  --> float  --> double  --> long double (16个字节)


        (2) % 取余 
            在C语言中, %的两个操作数必须都是 整数  

                5%3    ==> 2
                -5%3   ==> -2       // -5 ÷ 3 = -1 ..... -2 
                5%-3   ==> 2 
                -5%-3  ==> -2
            结论: 余数的符号 和 被除数的符号 一致 
            

        (3) 自增 ++ , 让这个操作数的值加1 
            自减 -- , 让这个操作数的值减1 

                注意: 
                    1) 自增和自减 只能作用于 变量 
                        i++;        // i = i+1;
                        5++;        // 5 = 5+1;     error 
                        (a+b)++;    error 
                        (a++)++;    error 

                    2) 前置 和 后置 区别 

                                整个表达式的值      执行完之后i的值 
                        i++         i                   i+1
                        ++i         i+1                 i+1
                        i--         i                   i-1
                        --i         i-1                 i-1 

                            例子: 
                                a = i++;    --->    {
                                                        a = i;
                                                        i = i + 1;    
                                                    }

                                b = ++i;    --->    {
                                                        i = i+1;
                                                        b = i;
                                                    }

                        练习: 
                            1)
                                int i = 5;
                                int a = i++;        // a = 5     i= 6
                                int b = ++i;        // b = 7     i= 7
                                int c = i--;        // c = 7     i= 6
                                int d = --i;        // d = 5     i= 5

                            2) 
                                int i = 6;
                                printf("%d %d\n", i++, ++i );   //6 8 实际结果是 7 8 

                                    printf()函数中的计算顺序是 从右至左 , 而 打印是从左至右 
                                            但是 不同的编译器 也会导致结果不同 

                                    ++/-- 前置返回的是i本身的值, 后置返回的是缓冲区的值(临时对象的值)

                                printf("%d\n", i++ );
                                printf("%d\n", ++i );


    2)关系运算符 
        用来判断两个表达式的数值大小关系的运算符 
            双目运算符, 结合性:从左至右 

            >  >=  ==  <=  <  != 

        关系表达式:
            用关系运算符连接操作数的表达式 
            关系表达式的值只有两种情况: 1(关系成立), 0(关系不成立)

            例子: 
                    5>3             -->  1(关系成立)
                    1+2 > 0         -->  1(关系成立)
                    5>4>3           -->  0(关系不成立) 

                        --> 5>4>3 
                        --> (5>4) > 3 
                        -->  1  >  3 
                        -->  0


    3)逻辑运算符 
        表达某种数理逻辑的运算符 
            &&  逻辑与      双目运算符  "并且"      结合性:从左至右 
            ||  逻辑或      双目运算符  "或者"      结合性:从左至右
            !   逻辑非      单目运算符  "取反"

        逻辑表达式:
            有逻辑运算符连接操作数的表达式 
            逻辑表达式的值只有两种情况:  1(真,非0),  0(假)

            任何非0的数都表示真,但是 逻辑表达式为真,其值为1  

            例子: 
                int a=4, b=5;

                a && b      --> 1 
                a && 0      --> 0       只要有一个为0,整个表达式就为0 
                a || b      --> 1
                1 || a      --> 1       只要有一个为1.整个表达式就为1 

                0与上任何数都为0, 1或上任何数都为1  

            练习: 
                int a=1, b=2, c=3, d=4;
                int m=1, n=1;
                (m = a>b) && (n = c>d);
                printf("%d %d \n", m, n);   // 0  1   惰性运算 


            惰性运算:
                如果事先已经知道了表达式的值,那么它就不会继续运算后面的表达式了 

                比如: 
                    a && b && c 
                        只有当a的值为真(非0), 才会去计算b的值
                        只有当a和b的值都为真(非0),才会去计算c的值 

                    a || b || c 
                        只有当a为假(0)时, 才会去计算b的值
                        只有当a和b的值都为假(0)时, 才会去计算c的值 

            练习: 
                请用逻辑表达式 来判断某一年是否为闰年 
                    1)能够被4整除 但是不能被100整除
                    2)能够被400整除

                    int year;
                    
                    if( ( year%4 == 0 &&  year%100 != 0 ) || year%400 == 0  )
                    {
                        printf("Yes\n");
                    }

       

    4)位运算符 
        位运算符是按bit位进行运算的
            注意: 位运算符 只能作用于整数 

            ~   按位取反
            &   按位与 
            |   按位或
            ^   按位异或
            <<  按位左移 
            >>  按位右移  

                只有 按位取反~ 是单目运算符, 其余的都是 双目运算符, 结合性:从左至右 

                运算步骤: 将整数分解成补码(二进制序列), 然后再去按bit位进行运算,没有借位和进位 

        例子: 
            (1)按位取反 ~ 
                0 --> 1
                1 --> 0

                    int a = ~3;
                    printf("%d\n", a );
                    printf("%u\n", a ); 

                        3       00000000 00000000 00000000 00000011 
                            ~   11111111 11111111 11111111 11111100     a在内存中的存放形式 

                            %d : 补码还原 
                                    a   11111111 11111111 11111111 11111100 
                                    -1  11111111 11111111 11111111 11111011 
                                    ~   00000000 00000000 00000000 00000100     绝对值的原码  4 
                                    -->  -4 
                            
                            %u :  2^32 - 4 

                    int a = ~(-3);
                    printf("%d\n", a );
                    printf("%u\n", a );
                        
                        |-3|    00000000 00000000 00000000 00000011
                            ~   11111111 11111111 11111111 11111100
                            +1  -----------------------------------------
                                11111111 11111111 11111111 11111101     -3的补码 

                            ~   00000000 00000000 00000000 00000010     a在内存中的存放形式 

                            %d : 符号位为0, 为正数, 直接输出 --> 2 
                            %u :  2 

            
            (2)按位与 & 
                    a   b      a&b 
                    1   1       1
                    1   0       0
                    0   1       0
                    0   0       0 
                结论: 只有两个bit为都为1时,结果才为1,否则就为0      "有0则0,全1为1"

                例子: 
                    int a = 3 & 5;
                    printf("%d\n", a );     // 1
                    printf("%u\n", a );     // 1

                        3   00000000 00000000 00000000 00000011
                        5   00000000 00000000 00000000 00000101 
                         & -------------------------------------------
                            00000000 00000000 00000000 00000001     --->  1 

                结论: 
                    任何一个bit位与0进行 按位与&运算时, 结果都为0 
                        x & 0  ==> 0 
                    
                    任何一个bit位与1进行 按位与&运算时, 结果都保留原值 
                        x & 1  ==> x  


            (3)按位或 | 
                    a   b      a|b 
                    1   1       1
                    1   0       1
                    0   1       1
                    0   0       0 
                结论: 只有当两个bit位都为0时,结果才为0,否则就为1    "有1则1,全0为0" 

                    例子: 
                        int a = 3|5; 
                        printf("%d\n", a );     // 7 

                            3   00000000 00000000 00000000 00000011
                            5   00000000 00000000 00000000 00000101
                             | ------------------------------------------
                                00000000 00000000 00000000 00000111   --->  7

                结论: 
                    任何一个bit位与0进行 按位或|运算时, 其结果保留原值
                        x | 0  ==>  x 

                    任何一个bit位与1进行 按位或|运算时, 其结果都为 1 
                        x | 1  ==>  1 


            (4)按位异或 ^ 
                异或: 求异 "相同为0,不同为1"

                    a   b      a^b
                    1   1       0
                    1   0       1
                    0   1       1
                    0   0       0

                    例子: 
                        int a = 3 ^ 5;
                        printf("%d\n", a );       // 6 

                            3   00000000 00000000 00000000 00000011
                            5   00000000 00000000 00000000 00000101
                             ^ ------------------------------------------
                                00000000 00000000 00000000 00000110     --> 6 

                结论: 
                    任何一个bit位与0进行 按位异或^运算时,其结果保留原值 
                        x ^ 0  ==>  x 

                    任何一个bit位与1进行 按位异或^运算时,其结果取反 
                        x ^ 1  ==>  ~x 

                    练习: 
                        1)交换两个整数a和b的值 
                            int a = 5;
                            int b = 6;

                            方法一: 临时变量法 
                                int temp;
                                temp = a;
                                a = b;
                                b = temp;

                            方法二: 异或 
                                a = a ^ b;
                                b = b ^ a;
                                a = a ^ b;

                                    ==================
                                        a   0000 0101   5 
                                        b   0000 0110   6 
                                        ^   0000 0011   3   --->  a = a ^ b;

                                        b   0000 0110   6
                                        a   0000 0011   3
                                        ^   0000 0101   5   ---> b = b ^ a;

                                        a   0000 0011   3 
                                        b   0000 0101   5
                                        ^   0000 0110   6   ---> a = a ^ b;  

                            方法三: 
                                a = a + b;
                                b = a - b;
                                a = a - b;


            (5)按位左移 << 
                按bit位整体向左移 

                    a << n 
                        规则: 
                            把a转换成二进制bit序列(补码), 再按bit位整体向左偏移n位
                            高位直接舍弃掉n个位,低位补n个0 

                    例子: 
                        char a = 5 << 3;

                            5    0000 0101                          
                            <<1  0000 101 0     --> 0000 1010  --> 10  -->  5 * 2^1 
                            <<2  00 0101 00     --> 0001 0100  --> 20  -->  5 * 2^2
                            <<3  0 0101 000     --> 0010 1000  --> 40  -->  5 * 2^3
                            <<4  0101 0000                     --> 80  -->  5 * 2^4 

                    结论: 
                        如果按位左移舍弃的高位全是0,那么左移n位之后,其值就变为 原值 乘以 2的n次幂 

                    练习: 
                        假设有一个整型变量a,要把a的第5bit位 变为0, 其他bit位保持不变 

                            a   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 
                            
                            &   11111111 11111111 11111111 11011111 
                            ~   00000000 00000000 00000000 00100000 
                                1<<5 

                            --> xxxxxxxx xxxxxxxx xxxxxxxx xx0xxxxx 

                        ==>  a = a & ~(1<<5);


            (6)按位右移 >>
                按bit位整体向右移

                    a >> n 
                        规则: 
                            把a转换成二进制bit序列(补码), 再按bit位整体向右偏移n位
                                低位直接舍弃n位,高位补什么呢? 

                                如果无符号的概念,高位直接补n个0 
                                如果有符号的概念,高位补n个符号位 

                    例子: 
                        (1)
                            int a = -1;
                            a = a >> 31;
                            printf("%d\n", a );
                            printf("%u\n", a );

                                |-1|    00000000 00000000 00000000 00000001 
                                    ~   11111111 11111111 11111111 11111110
                                    +1  11111111 11111111 11111111 11111111   -1在内存中的存放形式 

                                        a是有符号的int,且符号位为1 
                                >>31    11111111 11111111 11111111 11111111

                                    %d : 补码还原 --> -1 
                                    %u : 2^32 - 1 

                        (2)
                            unsigned int a = -1;
                            a = a >> 31;
                            printf("%d\n", a );
                            printf("%u\n", a );

                                |-1|    00000000 00000000 00000000 00000001 
                                    ~   11111111 11111111 11111111 11111110
                                    +1  11111111 11111111 11111111 11111111   -1在内存中的存放形式

                                        a是 unsigned int 
                                 >>31   00000000 00000000 00000000 00000001 

                                 %d : 1 
                                 %u : 1 


    5)赋值运算符 = 
        双目运算符
        结合性: 从右至左 

            a = x  
                把x的值求出来,再把这个值 赋值给a 

            赋值运算符要求左边的操作数必须是一个可写的地址 (左值lvalue)

                5 = 3;      //error 
                2+3 = 5;    //error 
                i++ = 5;    //error 
                i = 5;      // OK 

            赋值表达式: 
                由赋值运算符连接操作数的表达式 
                赋值表达式的值就是最后赋值给左边变量的那个值 

                    a = b = 6;
                --> a = ( b = 6 );

            注意: 
                赋值时 涉及到类型转换,赋值运算符右边的值 需要转换成 左边变量的类型 
                左边变量的类型 即 赋值表达式的结果的类型 

                    float a = 1;

            复合赋值运算符
                赋值运算符 可以和算术运算符,位运算符 组成 复合赋值运算符 

                    +=  -=  *=  /=  %=  >>=  <<=  &=  |=  ^=  ~=  

                    例子: 
                        i += 6;     ==>  i = i + 6;


    6)条件运算符 ?:

        ?:   三目运算符, 结合性: 从右至左 

            语法: 
                表达式1 ? 表达式2 : 表达式3 

            求值顺序: 
                先计算表达式1的值,
                    如果表达式1的值为真(非0), 则整个表达式的值 就为 表达式2 的值
                    如果表达式1的值为假(0), 则整个表达式的值 就为 表达式3 的值

            例子: 
                int a = 5>4 ? 2 : 0;        // a --> 2 


    7)逗号运算符 , 
        双目运算符, 结合性: 从左至右 

            语法: 
                表达式1, 表达式2 
            求值顺序: 
                先求表达式1的值,再求表达式2的值,整个逗号表达式的值为 表达式2的值; 

                int a=5;
                int b=6;
                a = (a=7,b=8);
                printf("a = %d\n", a );     // 8 

        逗号表达式的扩展形式: 
            表达式1, 表达式2, 表达式3, .... 表达式n 
        求值顺序:
            先求表达式1的值, 再求表达式2的值, ... 最后求表达式n的值
            整个逗号表达式的值为 表达式n的值 

    
    8)求字节运算符 sizeof() 
        单目运算符 
        用来求一个对象或者类型所占的内存空间的字节数 

            例子: 
                sizeof(char)  -->  1 
                sizeof(int)   -->  4 
                sizeof(5)     -->  4 
                sizeof(1.0)   -->  8 (double)
                sizeof(1.0f)  -->  4 (float) 

                short s;
                sizeof(s+1)  -->  4 (int)   

            
        =======================
            求数据类型 typeof() 

                如果有一个数据x, 这个数据x的类型 typeof(x)  --> x的数据类型 

                例子: 
                    int a = 0;      //定义了一个整型变量a 

                    定义一个和变量a 类型一样的变量 

                        typeof(a) b;    //typeof 适用于 对未知类型变量的定义 

                    typeof(a) --> 求对象a的数据类型 
                                -->  int 

                    typeof(3)  -->  int 
                    typeof(3.0) --> double 


    9)指针运算符 
        & 取地址符  (单目运算符)
        * 指向符(解引用)  (单目运算符)

    10)分量运算符 (成员选择运算符)
        . 
        ->  

            引用结构体的成员变量
                结构体变量名.成员名
                结构体指针->成员名

    11)下标运算符 [] 
        引用数组的元素 
            int a[10];      //数组a, 有10个int类型的元素 
                a[0], a[1], ... a[9]

    12)强制类型转换运算符 () 
        语法: 
            (数据类型)对象

            例子: 
                float a = 3.6;
                int b = (int)a;     // 3 


        
3.优先级 

    我们在运算一个表达式的时候,先看优先级,再看是否有惰性运算,再看结合性 

            运算符              结合性                  几目运算符 

        ()  []  ->  .           从左至右 
        !  ~  ++  --            从右至左                单目运算符 
        *  /  %                 从左至右                算术运算符 
        +  -  
        <  <=  >  >=            从左至右                关系运算符 
        ==  !=  
        &  ^  |  <<  >>         从左至右                位运算符 
        &&                      从左至右                逻辑运算符  
        ||
        ?:                      从右至左                条件运算符(三目运算符)
        =  +=  -=  *=  /=       从右至左                赋值运算符 
        ,                       从左至右                逗号运算符 

          

   
            (1)取整型变量x中 第p个bit开始的n个bit 

                假设p=3, n=4 

                xxxxxxxx xxxxxxxx xxxxxxxx x dcba xxx
            >>p xxxxxxxx xxxxxxxx xxxxxxxx xxxxdcba
             &  00000000 00000000 00000000 00001111 

            1   00000000 00000000 00000000 00000001
            <<n 00000000 00000000 00000000 00010000     // 2^n   -->  1<<n 
            -1  00000000 00000000 00000000 00001111

                x = ((1<<n)-1) & (x>>p) ;

            (2)将整型变量x中 第p个bit开始的n个bit 取反,其他bit位保持不变 

                    x ^ 0 = x 
                    x ^ 1 = ~x 

                xxxxxxxx xxxxxxxx xxxxxxxx x dcba xxx
            ^   00000000 00000000 00000000 0 1111 000 

            1   00000000 00000000 00000000 00000001
            <<n 00000000 00000000 00000000 00010000     // 2^n   -->  1<<n 
            -1  00000000 00000000 00000000 00001111
            <<p 00000000 00000000 00000000 01111000

            --> xxxxxxxx xxxxxxxx xxxxxxxx x ~d~c~b~a xxx 

                x = x ^  ( ((1<<n)-1)<<p );


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值