C语言基础篇(二)运算符

导航:
  2.1 算数运算符
  2.2 逻辑运算符
  2.3 位运算
  2.4 赋值运算
  2.5 内存访问符号
----->x<------------->x<--------------->x<--------------->x<------------->x<-----
 
2.1 算数运算符
            -- +, -
                在 +(-) 两边的数据类型,尽量一致.比如: A + B, A和B的类型尽量一致, 在定义加法的时候,可以加小括号(),这样
                可以避免语法逻辑错误 .
 
            -- *, /, %
                在cpu中, 其实是没有 乘法 和 除法 的. cpu只能通过软件模拟的方式, 来翻译这种操作.
                比如 : int a = b *10; cpu会用很多的模拟算法, 来解释 * 这种算法. 效率是非常低的 .
                如果是我们自己开发逻辑程序的话, * 和 / 是无法实现的. 所以 * 和 / 尽量少用 .

                % 是求模. 实际上就是取余数 .
                求模的特性就是
                res = x % n; 那么 res 的范围就是 0 ~ (n-1)
                    什么时候用呢?
                    给一个任意的数字, 可能就是随机数, 这个数字我们要得到一个 1 ~ 100 里面的数,
                    res = x % 100; //0 ~ 99;
                    res += 1;       // 1 ~ 100;
                
        2.2 逻辑运算符
            真 和 假 的选择. ( 非0 和 0 )
            -- |, ||; &, &&
                问: A || B 是否等价于 B || A ??
                答: 不等价. cpu 看到 A 已经是真了, 就不会去计算B的值. 同样 (A && B) != (B && A)
                ----------------------->
                int main (void){

                    int a = 10;
                    int res;
                    res = ((a == 10) || printf("我并不会被执行,因为(a == 10)成立,为真,就不会来判断我了. \n"));
                    return 0;
                }
                -----------------------<

            -- >>, >=, <, <=
                略 .
 
            -- !
                原本如果是真, 加了!号后就是假. 对比取反~ .
                !:  char a = 0x01;   !a ==0x00;                  //原本非零的真,!后就是为0的假 .
                ~: char b = 0x01;   ~b == 11111110 == 0xfe;   //按位取反,0~1 1~0.

            -- ?, :
                常用与三元运算符 .
        2.3 位运算!!!
            位运算是硬件计算必须使用的方法, 要重点掌握!!
            -- <<, >>
                移位.移位是在硬件里面常用到的方法.移位分为 有符号 和 无符号 的移位.
                unsigned char a = oxff;
                左移 n 位, 就是 乘以 2的n次方 . a << 3 -> a* (2的3次方) .
                右移 n 位, 就是 除以 2的n次方 . a >> 3 -> a/ (2的3次方) .
                这种算法速度非常快.
                但是对于有符号位来说,
                第一位是符号位,无论怎么移动, 符号位 是不会改变的 .

            -- &, |, ^
                !!!硬件 设置位 和 屏蔽位 的操作 .
                (1) 屏蔽位 & .
                    char a = 0x34; --> 0011 0100
                                    a & 0xf0:
                                        0011 0100
                                    &   1111 0000
                                    --------------
                                        0011 0000
                    从这边可以知道,因为 a & 0xf0,那我的目的就是保留高4位,屏蔽低 4位.(又称作清零)

                (2) 设置位. | .
                    char a = 0x34; --> 0011 0100
                                    a | 0x02:
                                        0011 0100
                                    |   0000 0010
                                    --------------
                                        0011 0110
                    通过或操作,我已经将 0011 0100 设置成了 0011 0110 .

                (3) 实际应用 .(建议对以下算法用笔算理清楚)
                    有一个硬件资源,8位(0~7) . 它的第2位控制led的开关 ,它的第5位,控制蜂鸣器的开关 .其他位是未知,但是很重要并且不能改变的数据位 .
                    现在,我要让第2位置1打开, 第5位置0关闭 .
                        现在 char a = xx(fm)x x(led)xx
                    第一步: 清零. 无论led现在是什么状态, 先清零, 再置位 .
                        将 0000 0001 << 2 --> 0000 0100
                        取反. 1111 1011
                        &运算 . a & 1111 1011 --> xx(fm)x x0xx    (置零成功)
                    第二步: 置数.
                        将 1 << 2 --> 0000 0100
                        |运算 . xx(fm)x x0xx | 0000 0100 --> xx(fm)x x1xx (置数成功)
                    现在,我们已经在不影响 其它位 的情况下,成功地将 第2位 置1 .
                    同样 将第5位置零,可以参考清零做法 .
                        将 1 << 5 --> 0010 0000
                        取反. 1101 1111
                        &运算 . xx(fm)x x1xx & 1101 1111 --> xx0x x1xx
                    
                (4) 总结: << >> & | 这四种运算搭配工作就是 (清零) 和 (置数) !!!!!
                            
                            先清零 ---> 再置数

                    清零: 我要清零第 n 位. char a ; 
                    a &= ~(1<< n)
                    置数: 在清零的基础上,将第n位置 1.
                    a |= (1<< n)

            -- ~
                按位取反 .
            
        2.4 赋值运算
            =, +=, -+, &=, |= ...

        2.5 内存访问符号
            其实 程序 就是cpu 跟 内存 打交道,但是怎么打交道呢?就是访问内存的意思.于是就有了访问内存的符号 .
            -- ()
                ()有两种用法,一种是限制符,用来划分运算的优先级 3*(2+4)
                另一种就是内存访问的意思,一般用于函数. int func().

            -- []
                很多人看到这个,就能想到数组.其实在我们看来,没有所谓的数组,数组的本质实际上就是一段内存空间 .
                多余的描述只会让人限制了它的意义 .
                int a[16]; a[0] = 1; []的作用是通过 a 的地址,找到a的内存空间,然后根据下标0进行偏移,
                最终锁定a[0]这个内存空间,大小是 int 32位,最后将这个内存 置 1. a[0] = 0x0001;

            -- {}
                (1) 函数体的限制符,限制一个函数体的内存空间大小.
                (2) 结构体 共用体等的空间限制.

            -- ->和.
                ->和. 是 自定义空间(结构体) 不同变量的访问方法 .
                
                -> 是地址访问 .
                . 是变量访问 .
                举例:
                                struct school {
                                    int 校长工资;
                                    struct teacher 李老师;
                                    struct teacher 王老师;
                                };

                                struct teacher {
                                    int 工资;
                                };
                    上面是两个结构体,其中,teacher结构体在school这个结构体中被声明 .
                    使用:
                        struct school 希望小学;
                        希望小学.校长工资 = 1w;         //结构体的直接成员变量可以用 . 来访问 .
                        希望小学 -> 李老师.工资 = 5000;  //如果是跳转到另一个结构体,实际上是访问另一个内存空间,要用地址访问符 ->
                        希望小学 -> 王老师.工资 = 5000; //同上.


            -- &和*
                &后面跟数字是与运算 ,后面跟变量是取地址.
                比如 int a; &a就是取a得地址, 常用于 scanf("%d", &a); 就是从键盘获取一个整形数值,然后赋给a指向的哪个内存空间,也就是a的值.

                * 这可能是最恐怖的,但其实也是最亲切的.竟然有一种看到*我就放心了的感觉...
                * 要区别两种场景  声明 和 使用.

                    --------------------------------------------------
                        首先我要解释一下,什么是 声明 和 使用.
                        声明 就是在内存空间中为一个变量 和常量 开辟一个内存空间.
                            int a;
                            char b;
                            char name[5]; 这些都是声明.叫做 声明变量,也有声明函数的.因为函数也是一段内存空间,这里就先不谈.

                        使用 就是将声明好的变量进行使用 .
                            a = 100;
                            b = 'k';
                            strcpy(name,"kmist",5);等等...
                    ----------------------------------------------------
                指针也分为 声明 和 使用 .
                
    (1) 声明
                        声明指针变量的时候,我们用到*,其意义是告知,这是一个指针变量.
                        int *p;
                        char *chp;  //区别 char ch; 多了一个*号,就是告知,这是一个指针变量 .
                        int func(char *p){....} //多了一个*号,就是告知,这是一个指针变量 .

    (2) 使用
                        在声明中,有*告知这个一个指针,但是在使用中,有 *号,是 "访问 指针 指向 的 内存地址" 的意思.
                        int *age;
                        *age = 100;
                        注意:这里应该这样解读: 我声明的一个指针, 这个指针指向了一个int类型的空间.
                        这个空间的地址,叫做age,这个地址本身是一个内存地址,只不过我为他赋予了一个叫age的名字.
                        至于这个空间里面的具体内容, 就是 *age .
posted @ 2018-11-03 01:43  kmist  阅读(474)  评论(0编辑  收藏  举报