作者:老余
联系方式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
综上所述:
- static修饰的变量。只会初始化一次,因为值会在该.c文件里能重复使用,不会立即销毁的。
- 全局变量默认是有static修饰的
- 局部变量使用static可以有初始值。该初始值则是该数据类型的初始值
- 使用static修饰局部变量。该局部变量在函数和相互调用的时候,不会被销毁,值依然存在
- 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;
}
位运算符
这里主要有三个运算符:&、|、^
&
与的意思。也就是并且的意思。当然这个运算符也是取址运算符。具体的环境具体的意思不一样。这里我想补充一下双目运算符和单目运算符;
-
双目运算符。则是对两个变量进行操作的运算符。比如我们的+(加号)或者-、或者楼上说的关系运算符。都是对两个数进行操作的。例如a>b、a+b、a==b;这种对两个数操作的,我们叫做双目运算符
-
单目运算符:同理可得,只会对一个变量进行操作的运算符,比如楼上的楼上我们说的++和--,一般我们都是这样用的,比如++a或者a++,这里只对一个变量a进行操作,所以这种叫做单目运算符
-
三目运算符(条件运算符):既然都提到了单目和双目,这里就把三目也一起说说吧,三目运算符。由题可知,是对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、2优先级
- 乘除求余加减移, // 这句里面的运算符全归为算术运算符,移表示移位
- 关系等于不等于, // 关系运算符(< <= > >= !=)
- 按位与来异或或, // 位运算符优先级顺!序: & -> ^ -> |
- 逻辑与或条件弱, // 逻辑运算符优先级顺序: && -> ||,后面跟着优先级比较低(弱)的条件运算符
- 赋值逗号一点破。 // 赋值,逗号最低
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= |= | 从右到左 |
逗号 | , | 从左到右 |
这里建议看一看就是了。没必要死磕文字。