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 || 从左到右
条件 ?: 从右到左
赋值 = += -= *= /= %=>>= <<= &= ^= |= 从右到左
逗号 , 从左到右

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

原文地址:https://www.cnblogs.com/yuxiangqiezi/p/13128569.html