zoukankan      html  css  js  c++  java
  • C语言笔记(四):存储类、运算符

    作者:老余

    联系方式QQ:1316677086

    个人博客网址:www.yuxiaoshao.cn

    微信公众号:老余笔记

    存储类

    说实话,学校在拉课本的时候没有详细说关于这章的内容,但是由于复习需要,还是学习一下吧。这里首先要知道什么是存储类。是为了定义C中的函数以及变量的范围和声明周期,这里的范围可以理解成之前提到过的int的取值范围。声明周期后面再详细解释,就是一个变量的创建到销毁的过程;

    首先要知道有哪几个存储类:

    • auto:汽车的意思,但是这里为啥要用这个,我没有深究了
    • register:注册,登记
    • static:静态
    • extern:外部

    当然,这些存储类型也是c库里的关键字

    auto

    首先先了解一下auto存储类。该类是所有局部变量默认的存储类,也就说,所有的局部变量,包括函数里的参数,都是auto来管的。简单的来说,所有在函数里的变量或者常量,都是有一个auto来修饰的,虽然我们在定义的时候没有用到auto。但是其实在编译运行的时候,是有auto来修饰的。

    代码:

    #include <stdio.h>
    int main(){
    	int a ;
    	auto int b ;
    	return 0;
    }
    

    也就说,auto只能修饰函数和里的变量,只能用在{}里

    auto只能修饰局部变量,它也限制了该变量只能在当前的{}里使用,这也就是局部变量的原因

    register

    register 存储类用于定义存储在寄存器(cpu里用来放二进制代码的一片块空间)中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 '&' 运算符(因为它没有内存位置)。我的上篇博客,说是运行内存是rom,这里有个小错误,其实是ram因为我习惯了说rom。当然ram和rom具体是啥,就不要多想了。

    也就是说register修饰的变量,是在寄存器里开辟的空间来存放变量的,所以没有地址,不能用取址&运算符来使用该变量。但是网上有文档说,不一定是存储在寄存器里的,需要更具硬件来判断,所以这里就不要深究了。知道它是干嘛用的就是了

    记住一点,用了register修饰的变量或者常量,不能用&

    register可以修饰全局变量,也可以修饰局部变量

    static

    静态的意思。但是在c语言了是干啥的呢?这里简单的说一下,一般我们定义一个局部变量,他的生命周期就是他所在的{},如果这个{}已经运行完成了。那么这个局部变量就被销毁了。用代码解释一下

    #include <stdio.h>
    int hello(){
        //定义一个局部变量a,他的作用域范围就是这个hello函数。
        int  a = 100;
        //在每次调用hello的时候都对a进行加1
        a = a + 1;
        //将a的结果作为返回值
        return a ;
    }
    int main(){
        //第一次调用hello
        int b = hello();
       	printf(" b 是:%d
    ", b );
          //第2次调用hello
    	printf("hello函数里的a是:%d
    ",hello());
    return 0;
    }
    

    也就说,目前这种情况,在给b赋值的时候用到了hello()函数和在打印输出又调用了一次hello()函数。但是目前这种情况,hello中的a,在第一次b赋值的完成后,就被销毁了。在第二次调用的输出的时候,又是重新创建的变量a,所以a的值一直都是101;

    结果如图:

    使用static修饰的局部变量

    #include <stdio.h>
    int hello(){
        //定义一个局部变量a,他的作用域范围就是这个hello函数。
       static int  a = 100; //这里使用是static
        //在每次调用hello的时候都对a进行加1
        a = a + 1;
        //将a的结果作为返回值
        return a ;
    }
    int main(){
        //第一次调用hello
        int b = hello();
       	printf(" b 是:%d
    ", b );
          //第2次调用hello
    	printf("hello函数里的a是:%d
    ",hello());
    return 0;
    }
    

    这里就很神奇了。在第一次给变量b赋值后,a变量没有被销毁,而是在第二次打印输出的时候,接着之前的a的值进行运算。相当于一次循环。当然我这样说可能不太对,这样相当于第二次调用hello函数的a的时候的初始值是第一次的运算结果。也就说,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值,这个值不是固定的,而是根据上一次的结果

    结果如图:

    但是你可能会这样想,每次都是针对于同一个a进行操作,那么地址是一样的吧,其实不是这样,在a进行+1的时候,其实是将a所有的值都是存储在一个数组里的,每次调用hello函数,a就每增加1,那么这个每次新生成的a的值,是存储在一个数组里的。然后在每次用到a的时候,更具第几次调用hello函数,则将该索引位置的a的值返回给它。这里可不用深入理解。我是这样想的

    这里我们接着代码测试一下

    #include <stdio.h>
    int hello(){
        //定义一个局部变量a,他的作用域范围就是这个hello函数。
       static int  a = 100; //这里使用是static
        //在每次调用hello的时候都对a进行加1
        a = a + 1;
        //将a的结果作为返回值
        return a ;
    }
    int main(){
        //第一次调用hello
        int b = hello();
       	printf(" b 是:%d
    ", b );
          //第2次调用hello
    	printf("hello函数里的a是:%d
    ",hello());
    	printf("b的地址:%p
    ",b);
    	printf("hello函数返回的a的地址: %p
    ",hello());
    	printf("hello函数返回的a的地址: %p
    ",hello());
    return 0;
    }
    

    结果如图:

    你会发现地址是不一样的吧。但是我们如果不对a进行自加呢?也就是始终都是调用的一个a,那么地址就是小奶狗太难的

    如果我们不给局部变量赋初值呢?但是用来static修饰。之前说变量的时候说过。默认的局部变量是auto类型的。c会给没有赋初值的局部变量一个乱的值。但是用了static修饰呢?就会给他一个初始值,这个初始值就是根据变量类型来分配的。比如这里的是int,那么初始值就是0;

    下面用代码测试一下。

    #include <stdio.h>
    int hello(){
        //定义一个局部变量a,他的作用域范围就是这个hello函数。
       static int  a; //这里使用是static
        //将a的结果作为返回值
        return a ;
    }
    int main(){
        //第一次调用hello
        int b = hello();
       	printf(" b 是:%d
    ", b );
          //第2次调用hello
    	printf("hello函数里的a是:%d
    ",hello());
    	printf("b的地址:%p
    ",b);
    	printf("hello函数返回的a的地址: %p
    ",hello());
    	printf("hello函数返回的a的地址: %p
    ",hello());
    return 0;
    }
    

    你会发现,没有乱码。b的值是0;hello()的返回值也是0,当然这里的地址也是同一个地址,因为没有对a进行操作,都是调用的同一个a

    综上所述:

    1. static修饰的变量。只会初始化一次,因为值会在该.c文件里能重复使用,不会立即销毁的。
    2. 全局变量默认是有static修饰的
    3. 局部变量使用static可以有初始值。该初始值则是该数据类型的初始值
    4. 使用static修饰局部变量。该局部变量在函数和相互调用的时候,不会被销毁,值依然存在
    5. static修饰一个函数或者一个全局变量。只要该函数以及该变量是在一个.c文档中都可以使用

    extern

    之前在介绍了。是外部的意思。这里回忆一哈。这里就是声明的意思,是用来修饰局部变量的。他的实际用法就是,当你需要使用一个变量,这个变量是之前定义过的,而且是在该函数外部,你就可以用extern再次声明一个次变量。这样就能直接使用之前你定义的变量的值了。当然,extern也是能修饰全局变量以及函数的。如果是修饰全局变量以及函数,就需要在同一个工程项目中,有该全局变量以及函数的定义。当然可以不是同一个.c文件,反正你必须要在其他.c文件里有对该全局变量或者函数的定义;这里就 不详细举例子了。知道主要是用来声明变量的就OK

    运算符

    算术运算符

    数学里的四则运算的都知道吧,四则运算符也就是+-*/这几个,这里补充两个新的运算符++,以及--,读作加加、减减

    因为是和算术有关的,所以叫做算术运算符,还有一个百分号%叫做取余,也就是这7个吧。加减乘除就不用解释了吧。

    这里就简单的介绍一下这三种

    %

    取余,也就是求余数,C 语言中的取余运算只能针对整数,也就是说,% 的两边都必须是整数,不能出现小数,否则编译器会报错。

    另外,余数可以是正数也可以是负数,由 % 左边的整数决定

    • 如果 % 左边是正数,那么余数也是正数;
    • 如果 % 左边是负数,那么余数也是负数;

    ++

    是针对变量使用的,常量不能使用,因为常量的值已近定死了,只能是那个值,不能做增减操作,也不能赋值修改

    叫做自增,也读加加。当然咯。这个的意思就是+1的意思。例如我们定义一个常量A=10,在定义一个变量b=A。然后看代码

    #include <stdio.h>
    #define A 10
    int main(){
        int b = A;
        //++b;
        //b++;
        //pirntf("b的结果是:%d
    ",b);//结果是12=10+1+1
        printf("b++的结果是:%d
    ",b++);//结果是10 b的值10+1
         printf("++b的结果是:%d
    ",++b);//结果是12 b的值11+1
        return 0;
    }
    

    现在来剖析一下上面的代码。首先定义了一个常量 A 且给A赋初值10;然后在main函数里定义了一个变量b,将A的值赋值给b作为b的初值;

    然后打印出++b和b++的结果。

    这里重点来咯。主要是针对于加号和减号的位置要区分一下。这里先明白一点。无论加号在前面或者是在后面,b值都是会增加1的如果是先是运行了b++或者++b然后打印的b,b的结果都是会+1的;具体代码在注释部分。

    现在区分一下++在前面和在后面有啥区别吧。++在变量的前面,意味着用b自增后的结果参与运算。++在后面,意味着先用b没有自增的值进行运算,在进行自增也就是说无嫩怎样,都是会自增的。从上面代码看。第一个b++。++在后面。所有先用的b本身的结果进行运算,即打印的就是b本身的结果,则结果是10;但是b的值还是会自增的。所以在执行了b++后b的值是11;然后看第二个打印语句。++b即++在前面。是先进行自增。然后在用自增后的结果参与运算。因为执行了上一句。b的值已经被改变成了11,这里又因为是++在前面则是先执行的则先执行的自增。所以打印的是直接在11的基础上+1的结果

    给说个好记点的方式:++在前则先自增,++在后则后自增

    --

    这里就不详细解释了如果你理解了++,这个也就是-1

    --也就减减运算符,也就是自减的意思。也就是-1;--在前和在后和++一个道理,--在前,先自减,--在后,后自减

    关系运算符

    这里简单的谈谈关系运算符。所谓的关系,也就是>、<、==,当然这里的等于是双=,还有<=(小于等于)、>=(大于等于)、!=(不等于)由于c里面没有真正的布尔类型,这个布尔类型在数据类型里我有提到过。可以参考一下。在c中。非0数表示真即对,0是假即错。所有满足该关系的返回值就是1,不满足就是0;怎么算是满足呢?就是关系式成立,比如1>=1;1是大于等于1的吧。所以这个关系成立,则会返回一个1。当然这个1和0有啥子用。后面用到判断的时候就有用咯。一般我们不会吧这个返回的结果(0或1)打印出来,而是作为判断条件,进行判断

    代码:

    #include <stdio.h>
    int main(){
    int a = 4,b=10;
     printf("判断返回的结果(0或1):%d
    ",a>b);
         printf("判断返回的结果(0或1):%d
    ",a<b);
         printf("判断返回的结果(0或1):%d
    ",a==b);
         printf("判断返回的结果(0或1):%d
    ",a!=b);
    return 0;
    }
    

    位运算符

    这里主要有三个运算符:&、|、^

    &

    与的意思。也就是并且的意思。当然这个运算符也是取址运算符。具体的环境具体的意思不一样。这里我想补充一下双目运算符和单目运算符;

    1. 双目运算符。则是对两个变量进行操作的运算符。比如我们的+(加号)或者-、或者楼上说的关系运算符。都是对两个数进行操作的。例如a>b、a+b、a==b;这种对两个数操作的,我们叫做双目运算符

    2. 单目运算符:同理可得,只会对一个变量进行操作的运算符,比如楼上的楼上我们说的++和--,一般我们都是这样用的,比如++a或者a++,这里只对一个变量a进行操作,所以这种叫做单目运算符

    3. 三目运算符(条件运算符):既然都提到了单目和双目,这里就把三目也一起说说吧,三目运算符。由题可知,是对3个变量进行操作的。语法:(条件)?执行语句1: 执行语句2;例:

      #include <stdio.h>
      int main(){
          int a =4,b=2;     
      	a>b?printf("a是大于b的
      "):printf("a是小于b的
      ");
          return 0;
      }
      

    如果?前面的关系满足,则执行:前面的语句。如果不满足则执行:后面的语句;

    当然,可能有小伙伴说为啥你的printf后没有带;,这里我之前说咯哦“;”是结束符号,意思说,一个完整的语句只能有一个分号,当然,这里没有最后也是带有了分号的呢;算是一个完整的三目运算符

    好了,扯了上面的一大堆,应该对单目、双目、三目有所了解了吧。这里需要说的是&,在作为单目运算符的时候,比如我们的sacnf函数,看代码

    #include <stdio.h>
    int main(){
        int a ;
        printf("请您输入一个数");
        scanf("%d",&a);
        printf("你输入的数是:%d
    ",a);
    return 0;
    }
    

    解剖代码:首先定义了一个变量a,这a没有赋初值的, 当然我们使用的时候需要给a赋初值。所以呢?我们通过scanf函数对a进行赋初值,这里的&a,就是找到a的地址(在变量的时候我说到过。变量名其实就是指向的变量存储地址【静态区或全局区】)所以通过&符号,找到a的地址,直接将从键盘输入的数传给了a地址上,将a的值替换(没有赋初值是乱码);这个也是scanf实现的原理,当然底层是在stdio.h库里实现的,这里是直接调用可以不用了解这个划线的部分。好滴,这就是&作为单目运算符的作用,是取址

    现在来介绍一下&作为双目运算符的时候,例如在进行逻辑判断的时候,比如我们在三目运算符里使用;看代码

    #include <stdio.h>
    int main(){
    int math = 52,english=100;
        (math>60)&(english>60)?printf("全部及格
    "):printf("有一个或者多个不及格
    ");
    return 0;
    }
    

    代码剖析:这里首先我们用了关系运算符对每个科目进行判断,然后使用到了&运算符来表示是否都满足。因为&做为双目运算符的时候是and的意思也就就是都的意思这里吧一个括号看左一个整体,每个括号里单独判断,如果都是真,则执行:前面的语句,如果有一个是假或者都是假,则执行:后面的语句这个也就是物理里面的串联电路的感觉,只要有一非通路,则都走不通。

    这里需要明白一件事,是把括号里的关系运算符看成一个整体。关系运算符返回的结果只有两个一个是0一个是1,满足条件是1不满足条件是0,加入都满足条件,所以就是1&1;那么通过&运算符则返回一个1,则表示通过;如果是0&1或者是1&0;则都返回0,则表示都不通

    如果是用在两个数字上呢?

    这里的精髓就来了。也是一个运算考点吧

    比如我定义了两个整型变量a=4,b=10;那么a&b的结果是多少?

    这里没有用到关系运算符,所以需要将a和b分别表示为2进制数

    a的二进制:00000100

    b的二进制:00001010

    a&b的结果:00000000 换算成10进制则是0

    这个结果怎么来的呢?首先将a和b的二进制一一比较,都是1则写为1,其他的都是0,因为只有两边都是1的时候才能是通路嘛

    |

    这个和&的类似,是或的意思,和物理里的并联电路相似,有个是通路,那么都能走通。直接上代码

    #include <stdio.h>
    int main(){
    int math = 52,english=100;
        (math>60)|(english>60)?printf("全部及格
    "):printf("有一个或者多个不及格
    ");
    return 0;
    }
    

    这里由于是只要有一个是真(结果是非0)就行,那么执行的还是:前面的语句

    当然底层代码还是和&类似,将括号看做一个整体,这里第一个括号是假,则返回的是0,第二个括号是真,则返回的是1;那么就是0|1所以返回的1是一个非零数,那么就执行的是:前面的语句

    如果是两个数进行或运算呢?

    和&差不多

    比如我定义了两个整型变量a=4,b=10;那么a|b的结果是多少?

    这里没有用到关系运算符,所以需要将a和b分别表示为2进制数

    a的二进制:00000100

    b的二进制:00001010

    a&b的结果:00001110 换算成10进制则是14

    这个结果怎么来的呢?首先将a和b的二进制一一比较,只要有1则写为1,两个1也写为1,只有两个0才写作0,因为只有两边都是0的时候才是短路嘛

    ^

    异或,啥意思呢?就是表示两个数的 二进制进行比较,如果是相同的则返回0,不同则返回1;例如定义两个int型的变量,a,b并赋初值,直接上代码吧

    #include <stdio.h>
    int main(){
        //定义两个变量a、b并赋初值
        int a = 4,b =10;
    return 0;
    }
    

    代码剖析

    这里的a的值是4,二进制表示为00000100

    b的值是10,二进制表示为000001010

    如果你转换不来二进制,麻烦看我的变量和常量的博客

    好滴 这里得到了a和b的二进制数:现在将他们进行比较,相同的返回0,不同的返回1

    a的二进制:00000100

    b的二进制:00001010

    异或结果 :00001110 换成10进制后就是14

    如果考试叫求两个变量异或后的 结果,首先将两个变量分别编程2进制,默认8个位。然后将相同位置的写为0,不同的写为1;然后再换算成10进制

    当然最主要的一点是使用异或符号,能交换两个数的值

    代码如下

    int a = 4, b = 10;
    a =a^b;//得到异或的结果14 然后赋值给a ,现在a的值是14
    b =a^b;//得到异或的结果是4,然后复赋值给了b。现在b的值是4,a的值依然是14
    a =a^b;//得到异或的结果是10,然后赋值给a,b的结果依然是4,则交换成功了
    printf("a:%d
    ",a);
    printf("b:%d
    ",b);
    

    异或的结果,则是楼上的方式进行计算的

    ~

    这个叫做取反运算符,这个是单目运算符,只对一个变量进行操作的;取反,我们在进制换算的时候用到过哦。在进行负数的进制换算的时候,我们需要取得相应正数的二进制,然后进行取反,得到负数的原码,然后进行加一,就能得到负数的二进制数咯;

    好滴,这里首先我们写个小例子。先定义一个int型的变量a = 10;这个a是带符号的变量,而且是个正数

    然后打印出~a的值

    首先我们知道a的二进制是:00001010 00101000 00000101

    那么取反后的二进制就是: 11110101 很明显,这里的从左到右的第一个符号位是1,那么就是负数而且是原码,所以呢?这里需要用到负数二进制转换成十进制的知识咯,首先减一得到补码

    补码:11110100 然后取反得到反码,为啥这里要取反,因为之前我们获得的原码就是取反了的,所以这里取反就取回来了。(有点抽象哈)

    反码:00001011 然后变成十进制的数是11但是这个是符号所以说就是-11

    上代码

    #include <stdio.h>
    int main(){
     int a = 10;
        printf("%d
    ",~a);
    return 0;
    }
    

    好了,我知道可能脑壳有点晕,这就说个规律,如果是叫你求一个数的取反值;比如说有一个数a=20.。首先我们知道给的是一个正数20,那么~a就直接等于-21;如果是b=21那么~b=-22;如果c=-2那么~c= -1;如果d=-1,那么~d=0;这个规律就是,如果给的是正数,那么取反的值就是+1然后变成负数,如果给的是负数,那么取反的值就是直接变成相应的正数-1简单的归纳,就是正数取反,加一变负,负数取反,变正减一欧克这个取反算是拉扯完了

    <<

    有意思的来了。这个长得像两个小于符号的,叫左移位。因为是指向左边的。当然,这里底层还是对二进制进行操作

    比如我们有个int变量a = 10;然后求a<<2; 这个就相当于是10<<2;首先要知道它的二进制 是 00001010 然后从左到右看将第一个1和最后一个1出现的一堆,也就是101整体向左移动2位,也就是变成了00101000然后变成十进制是40,这个40就是移位后的值

    上代码

    #include <stdio.h>
    int main(){
     int a = 10;
        printf("%d
    ",a<<2);
    return 0;
    }
    

    如果是左边移动10位呢

    也就是a<<10那么还是先得到a的二进制也就是10的二进制:00001010,然后从左到右找到第一个1和最后一个1,这里是101,因为一个字节是8位,然后刺激的来了。int是多少字节,当然是4个字节啦。一个字节又是8位,所以int里有32个位置的,也就说8个一堆,有4堆:00000000 00000000 00000000 00000000,10的二进制其实是00000000 0000000 00000000 00001010,然后向左边移动了10位,然后就是00000000 00000000 00101000 00000000 然后变成十进制就是2的11次方加上2的13次方=2048,很刺激吧;但是考试不会这样考,面试也不会这么傻逼

    >>

    右移位。这个和左移动位换汤不换药。比如我有一个变量int型b=2,需要知道b>>3的值是多少(也就是2>>3因为这里的b就是2嘛)?然后我们需要知道2的二进制是00000010,向右边移动三位。这里需要从右边往左边数咯,第一个1到最后一个1中间的一坨都向右边移动3个位置,这里只有一个1,所以直接右边移动三位,也就是然后发现是这样的00000000 01 发现是这样的,超过右边的数咯。所以直接就是0咯。如果是移动1位,就是刚好是右边的最后最后一位,那么就是1,如果超过了右边的最后一位,那么结果都是0

    如果是负数呢?后面再说吧。懒得算了。

    这里注意,2>>1不等于1<<2二进制的移位,开玩笑呢?这种低级错误不要犯

    逻辑运算符

    这里主要有三个:&& || !分别叫做与或非

    &&

    和&很类似,但是这里&&只有与的意思,没有在二进制里进行操作,一般在逻辑表达式里运用,即在if等条件判断的时候 用

    他的原则是:&&左边的数如果是个非零数,以及&&右边的数是个非零数,则返回一个数字1,如果左边或者右边出现一个0则返回0;在c里0代表false,非零代表true。所以这里只做逻辑判断;

    #include <stdio.h>
    int main(){
        int a = 50,b = 90;
        (a>60)&&(b>60)?printf("都及格了
    "):printf("有一个或者多个不及格
    ");
    	printf("%d
    ", (a>60)&&(b>60));
    	return 0;
    }
    

    这里&&前面的括号里的结果是0,&&后面的逻辑判断结果是1,所以有一个0存在,都不能通路,则整体&&逻辑判断结果是0;

    ||

    和|按位与很类似。但是呢?这里也是指做判断使用,如果||左边或者右边有一个是非零数,那么 返回1,只有左右都是0的时候,才会返回0

    #include <stdio.h>
    int main(){
        int a = 50,b = 90;
        (a>60)||(b>60)?printf("都及格了
    "):printf("有一个或者多个不及格
    ");
    	printf("%d
    ", (a>60)||(b>60));
    	return 0;
    }
    

    这里||前面的括号里的结果是0,||后面的逻辑判断结果是1,所以有一个1存在,都能通路,则整体||逻辑判断结果是1;

    逻辑非运算符,也就是说,一个结果是假的变成真的,一个结果是真的变成假的

    实例代码:

    #include <stdio.h>
    int main(){
        int a = 50,b = 90;
        !((a>60)&&(b>60))?printf("都及格了
    "):printf("有一个或者多个不及格
    ");
        	printf("%d
    ", !((a>60)&&(b>60)));//查看逻辑判断结果
    	return 0;
    }
    

    这里原本该执行后面的语句,但是由于!运算符,所有执行的前面的语句,因为本来逻辑判断结果是0但是由于!的存在,则结果是1

    &&和&以及||和|的区别

    首先,&叫做按位与,而&&叫做与也就说,在逻辑判断的时候,才有相似之处,但是为啥&能处理与的逻辑,为啥还要来个&&呢?因为&&在逻辑判断的时候更加聪明一点,因为c里面代码是从左至右运行的&&如果识别到了左边的值是0,那么它就不会再&&右边的结果了。直接返回0即false同理。||如果识别到了左边的值是1,那么也就不管再执行||有右边的语句了直接返回1,而&在识别到了左边的值是0后依然会执行&右边的语句。|在识别到了左边的值是1后依然也会执行|右边的语句;这样在逻辑判断的时候就降低了判断效率。

    赋值运算符。

    这里简答的说一哈,常用的= ,也就是一般我们用的int a = 10;这个就是将10赋值给了变量a,当然还有+=、-=、*=、/=。。。基本的单目运算符都能这样用比如a+=b 即 a= a + b ; a/=b 即使 a = a/b ,后面的都是类似的,不详细将了,我直接贴网上找的。看一哈就ok

    运算符 描述 实例
    = 简单的赋值运算符,把右边操作数的值赋给左边操作数 C = A + B 将把 A + B 的值赋给 C
    += 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 C += A 相当于 C = C + A
    -= 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 C -= A 相当于 C = C - A
    *= 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 C *= A 相当于 C = C * A
    /= 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 C /= A 相当于 C = C / A
    %= 求模且赋值运算符,求两个操作数的模赋值给左边操作数 C %= A 相当于 C = C % A
    <<= 左移且赋值运算符 C <<= 2 等同于 C = C << 2
    >>= 右移且赋值运算符 C >>= 2 等同于 C = C >> 2
    &= 按位与且赋值运算符 C &= 2 等同于 C = C & 2
    ^= 按位异或且赋值运算符 C ^= 2 等同于 C = C ^ 2
    |= 按位或且赋值运算符 C |= 2 等同于 C = C | 2

    sizeof函数

    sizeof也叫求字节运算符,当然这里还是喜欢叫他sizeof函数

    sizeof()函数,是用来表示数据长度的一个函数,这个长度是绝对长度,这里先补给一个小知识,一般的 字符串后默认是带有后缀的,但是我们一般是不用打印,在sizeof函数里,所有的转义字符也占一个长度的空间,c编译和运行的时候会自动添加,就像我们用的换行 一样,其实也是占用一个长度的,可以用sizeof()来测试数据类型所占字节大小,看代码

    #include <stdio.h>
    int main(){
     char str [] ={"love
    "};
     printf("%d
    ",sizeof(str));
      printf("%d
    ",sizeof(int));
         printf("%d
    ",sizeof(char));
    	  printf("%d
    ",sizeof(short));
    
    return 0;
    }
    

    运算符优先级

    优先级,这里和数学里的优先级比较小相似

    括号成员是老大;      // 括号运算符 []() 成员运算符.  ->
    
    全体单目排老二;      // 所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算*、&
    
    乘除余三,加减四;    // 这个"余"是指取余运算即%
    
    移位五,关系六;     // 移位运算符:<< >> ,关系:> < >= <= 等
    
    等与不等排行七;     // 即 == 和 !=
    
    位与异或和位或;     // 这几个都是位运算: 位与(&)异或(^)位或(|)    
    
    "三分天下"八九十;  
    
    逻辑与,逻辑或;    // 逻辑运算符: || 和 &&
    
    十一十二紧挨着;    // 注意顺序: 优先级(||)  底于 优先级(&&) 
    
    条件只比赋值高,    // 三目运算符优先级排到 13 位只比赋值运算符和 "," 高
    
    逗号运算最低级!    //逗号运算符优先级最低 
    
    1. 初等单目一二级, // 初等运算符和单目运算符分别是第1、2优先级
    2. 乘除求余加减移, // 这句里面的运算符全归为算术运算符,移表示移位
    3. 关系等于不等于, // 关系运算符(< <= > >= !=)
    4. 按位与来异或或, // 位运算符优先级顺!序: & -> ^ -> |
    5. 逻辑与或条件弱, // 逻辑运算符优先级顺序: && -> ||,后面跟着优先级比较低(弱)的条件运算符
    6. 赋值逗号一点破。 // 赋值,逗号最低
    类别 运算符 结合性
    后缀 () [] -> . ++ - - 从左到右
    一元 + - ! ~ ++ - - (type)* & sizeof 从右到左
    乘除 * / % 从左到右
    加减 + - 从左到右
    移位 << >> 从左到右
    关系 < <= > >= 从左到右
    相等 == != 从左到右
    位与 AND & 从左到右
    位异或 XOR ^ 从左到右
    位或 OR | 从左到右
    逻辑与 AND && 从左到右
    逻辑或 OR || 从左到右
    条件 ?: 从右到左
    赋值 = += -= *= /= %=>>= <<= &= ^= |= 从右到左
    逗号 , 从左到右

    这里建议看一看就是了。没必要死磕文字。

  • 相关阅读:
    iot 表 主键索引叶子块包含了表所有数据
    iot 表索引dump《2》
    iot 表索引dump《2》
    heap表和iot表排序规则不同
    heap表和iot表排序规则不同
    ActiveMQ学习总结(4)——业界消息队列简介
    主宰全球的10大算法
    主宰全球的10大算法
    主宰全球的10大算法
    SVN学习总结(1)——SVN简介及入门使用
  • 原文地址:https://www.cnblogs.com/yuxiangqiezi/p/13128569.html
Copyright © 2011-2022 走看看