• C和C指针小记(八)-操作符、左值右值


    1、移位操作符

    移位操作符分为左移操作符(<<)和右移操纵符(>>)
    对于无符号数:左右位移操作都是逻辑位移
    对于有符号数:到底是采用逻辑位移还是算术位移取决于编译器.如果一个出现使用了有符号数的右移操作,它就是不可移植的.

    对于左移操作:右边空出来的位数用0补齐.
    对于右移操作:如果是逻辑位移,左边移入的位用0填充;如果是算术位移,左边移入的位由原先该值的符号位决定,符号为为1则移入的位均为1,符号为为0则移入的位均为0.

    注意:
    a << -5;
    这种形式的移位由编译器决定.它产生的效果是不可预知的.

    2、位操作符

    位操作符对它们的操作数的各个位执行与,或,异或,补等逻辑操作.
    包括: AND OR XOR, 分别代表 与,或,异或,(补)
    对应的操作符是: & | ^ ~

    3、位操作的应用

    3.1 统计输入字符中的字符个数,单词个数,换行符个数

     /*
         * 统计输入的字符串中 行数,制表符,字符的个数,注意没有break,因为美出现一次换行符就表示单词个数和字符个数也增加了,每出现一次 空字符或制表符,字符个数也增加了
         */
        int ch;
        int lines = 0;
        int words = 0;
        int chars = 0;
        while ((ch = getchar()) != EOF) {
            switch (ch) {
                case '
    ':
                    lines += 1;
                case ' ':
                case '	':
                    words += 1;
                default:
                    chars += 1;
            }
        }
    
    

    3.2 把一个整数的某位数置为1

     //把value1 的第五位数置为1
        int value1 = 5;
        printf("value1: %d ",value1);//5 b0101
        value1 = value1 | 1 << 5;//把value1 的第五位数置为1
        printf("value1: %d
    ",value1);//37 b10101
    

    3.3 把一个数的某位数置为0

        //把value2 的第5位数置为0
         int value2 = 32;
        printf("value2: %d ", value2);//32 b10000
        value2 = value2 & ~( 1 << 5);
        printf("value2: %d
    ", value2);//0 b00000
    

    3.4 测试整数的二进制序列某位是否为1

        //测试第4位是否为1
        int value3 = 15;
        printf("value3: %d
    ", value3);//15
        printf("value3 的第4位为 %d 
    ",(value3 & 1 << 4));//value3 的第4位为 0
    

    3.5 返回函数参数值中值为1的位的个数

    //返回函数参数值中值为1的位的个数
    int count_one_bits(unsigned value) {
        int ones;
        for(ones = 0; value != 0; value >>= 1){
            if ((value & 1) != 0) {
                ones += 1;
            }
        }
        return ones;
    }
    
    
    

    4、赋值操作符 =

    需要注意的点:
    a = x = y +3;
    如果x是一个字符型变量,那么 y+3的值就会被截去一段,以便容纳与字符类型的变量中.那么a所赋的值就是被截取后的值.
    还有之前提到的:
    char ch;
    while((ch = getchar()) !=EOF)
    因为EOF需要的位数比字符型值所能提供的位数要多,这也是getchar返回一个整型值而不是字符值的原因.然而,把 getchar() 的返回值先存储与ch中将导致它被截断.
    然后这个被截断的值被提升位整型并与EFO进行比较.这段存在错误的代码在使用有符号字符集的机器上运行时,如果读取了一个值位377的字节时,循环将会终止.因为这个值截短再提升之后与EOF相等.当这段代码在使用无符号字符集的机器上运行时,这个循环将永远不会终止.

    此外还有复合赋值符, 它可以是程序变得简洁
    += -= *= /= %=
    <<= >>= &= ^= |=

    5、单目操作符

    ! ++ - & sizeof
    -- + * (类型)

    ! 逻辑反操作
    ~ 求补操作
    - 产生操作数的负值
    + 产生操作数的值,等于啥都不干
    & 产生操作数的地址
    * 简介访问,与指针一起使用,用于访问指针所指的值
    sizeof 判断它的操作数的类型长度,以字节为单位.操作数可以是个表达式(常常是单个变量),也可以是两边加上括号的类型名.
    如:sizeof(int) sizeof x.
    注意:sizeof(a = b+1) 并没有向a赋任何值.
    () 强制类型转换 (cast),用于显式的把表达式转换为另外的类型.
    ++

    这两个表达式有前缀和后缀形式.一般和赋值操作符一起使用.

    6、下标

    array[n] 等价于 *(array + (n))

    . 和 -> 都是用来访问一个结构的成员的.
    如果s是一个结构变量,那么 s.a 就访问s中名叫a的成员.
    当你拥有一个指向结构体的指针而不是结构本身,切欲访问它的成员时,就需要使用 -> 操作符,而不是. 操作符.

    7、左值和右值

    左值就是那些能够出现在赋值符号左边的东西,右值就是那些可以出现在赋值符号右边的东西.
    左值可是一个变量,也可以是一个表达式.但大多住表达式都能作为左值.表达式作为左值时,它的含义必须是一个特定的内存位置.
    例如:
    a = b + 1;// a 就是一个左值
    但是 b + 1 = a; // b+1就不能作为一个左值,
    int a[30];
    a[b + 10] = 0;//这里表达式就是一个左值
    再如:
    int a, *pi;
    pi = &a;
    *pi = 20;//这里 *p作为一个间接取值表达式 就是一个左值 它表示pi所指定来需要进行修改的位置.
    int c = *pi;//这里 *p 的含义就是提取当前存储与这个位置的值.

  • 相关阅读:
    文件操作工具类
    批量插入数据到 MySQL的几种方式
    C#队列学习笔记:RabbitMQ使用多线程提高消费吞吐率
    C#队列学习笔记:RabbitMQ延迟队列
    C#队列学习笔记:RabbitMQ优先级队列
    C#队列学习笔记:RabbitMQ实现客户端相互通讯
    C#队列学习笔记:RabbitMQ搭建集群
    C#队列学习笔记:RabbitMQ安装及使用
    C#队列学习笔记:RabbitMQ基础知识
    C#队列学习笔记:MSMQ入门二
  • 原文地址:https://www.cnblogs.com/wjw-blog/p/10384086.html
Copyright © 2020-2023  润新知