目录
我的讲述顺序将是运算符的先后顺序。如果按照我发文的顺序进行学习c语言的话,以下内容可能有些超前,但是希望你可以尽可能的去看懂并理解,我会把这篇当作自己的学习笔记和探索之路,再等到学习那些内容时就会恍然大悟,并且 更为深刻的理解。
操作符
一个运算式由算子和操作符构成,算子即平时运算所用的常量或变量,而操作符的介绍就构成了我们今天讲解的主要内容:
最优先级操作符
聚组括号
()
聚组括号的优先级最高,这个毋庸置疑,括号中的内容总是优先;
然而圆括号还有另一个含义,即函数调用:
type <函数名> (参数表){
......
}
在函数的基本格式中,传值所用的参数表就是利用括号作分界的;在数学领域,括号就是一个能以一己之力改变运算顺序的神奇符号,在计算机的运用中,它的作用被保留了下来,还得到了一定的扩展,后面所要提及的逗号运算符或其他语句中,括号都有很多的用武之地。
下标引用
[]
用于数组中的下标说明,是数组中不可缺少的重要组成标志,是数组中的访问成员符,可存放索引值对数组中指定元素进行访问。
结构访问
结构中的成员访问:
1.结构成员访问
.
在创建一个结构后,可用于对结构内容以:"struct <自定义结构名>.<成员>"的格式进行访问,对结构内部成员进行利用。
2.结构指针成员访问
->
这是一种较为便捷的方法,当然在结构中使用指针的基本方式也可以进行结构指针成员的访问。
以上介绍的操作符优先级(非特殊强调)都相同。
在这时,我们需要引入操作符的固有属性:
1.优先级
2.结合性
在同一个运算式中,各操作符优先级都相同,这时我们就需要要根据操作符的结合性来判断一个运算式中运算的先后顺序。
而在上述运算符中,它们的结合性是自左到右。
单目运算符
运算符 | 名字 | 格式 |
- | 负号表达式 | -表达式 |
~ | 按位取反运算符 | ~表达式 |
++ | 自增运算符 | ++i/i++ |
-- | 自减运算符 | --i/i-- |
* | 取值运算符 | *指针 |
& | 取地址运算符 | &变量名 |
! | 逻辑非运算符 | !表达式 |
在这些运算符中,由展示的类型为顺序我会依次介绍:
负号表达式的含义很简单,即取反值。
~是按位取反运算符,这个需要理解,在某些地方可以运用的十分巧妙,我们先讲它的作用:我们都知道,计算机内部的计算都是以二进制进行的,对于一个字节(1byte=8bit,一个比特存储一位数字)来说,如进行“~1”的运算,那么它的结果会是-1。这个结果是怎么得来的呢?让我们来看一下它的计算过程:
00000001
~
——————
11111110
像这样的二进制数字在计算机内,一共八位bit,在计算机中,我们可以通过二进制的表达方式得知11111110表达的数字是-2,按位运算是一种十分神奇的运算方式,正是因为计算机底层独特的计算逻辑才会诞生如此算法。由于按位运算的特殊性,许多优秀的程序员对这些看似无用的位运算符进行了深度延申,在scanf中就有体现:
while(~表达式){
......}
除了EOF(文件结束符)结束while循环外,还有另一种循环结束方式,即利用“~表达式” ,当表达式的值为-1时,根据按位取反的规则,它所得到的结果就会变成“0”,我们前面讲到过,当条件判断的值为0时,循环会自动退出并开始执行下一条语句。
虽然有些画蛇添足,但这确实是一种比较巧妙的方法,至今在某些程序中仍有使用,事实上,位运算的主要适用领域是单片机开发,因为针对底层逻辑,在单片机的某些元件中一个位的0或1就是一种状态,所以位运算的操作空间有了极大的发挥。
自增/自减运算符需要着重介绍。它的功能很奇特,以自增运算符为例:
i++=i,此式后i=i+1;
++i=i+1,此式后i=i+1;
++i的用法较为普通,而i++十分的有意思,正如介绍,若想短暂引入i,又希望在结束运算后令i+1,即可运用i++。最常见的用处是在for函数的结尾条件,这个需要我们自己在做程序时亲身实践。
‘*’操作符可以直接对指针的地址取其中的值进行访问,是指针必不可少的搭档。
‘&’的应用较常见还是在scanf和指针取地址,赋予指针一个值。
‘!"是逻辑非,在前面我们已经介绍过,非0的值在计算机内部逻辑值都被认为是‘1’,而另一个对立的逻辑值就是‘0’,逻辑非运算符就是对符号后的数据判断后取反,eg:
!3=0
当然,除了这些之外,还有一个特殊的运算符和它们的优先级相同:sizeof
它的作用是给出某个类型或某个变量在内存中所占据的字节数,一般以:sizeof(type)的形式给出。在后面的学习中,我们组建动态数组时,sizeof可以清晰地根据数组类型通过计算得知需要计算机内部提供的空间。
但需要特别注意的是:sizeof是‘静态’的,即不进行动态运算,这可以与先前讲到的i++进行联合理解:
在我们进行sizeof(a++)时,理应会在这句后,a=a+1,但实际上由于sizeof运算符的静态性,a++不会被执行;换句话说,sizeof只用来执行判断字节数的操作。
在上述所提及的操作符中,它们的优先级都相同,且结合性是自右向左。
双目操作符
乘除取余与加减
* | 相乘 |
/ | 相除 |
% | 取余 |
+ | 相加 |
- | 相减 |
这部分是我们小学就已经掌握并熟练运用的知识,需要提及的是‘%’是十分新奇的,它会取前数除以后数的余值,也叫做“取模”。它的前后必须是整数。
左移与右移
<<左移
>>右移
以右移举例:i>>j的含义是:i中所有的位向右移j位,在移位的过程中,数据的类型并不会发生转换,对于ungsigned类型,左边填入0,对于signed类型,左边填入原来的最高位(即保持符号不发生变化)。
事实上,在二进制中,集体向右移一位就代表着x/=2;同样的,如果是向右移动n位,就是x/=2^n。那左值自然就是取除数了,大家可以自己去尝试真知。
关系运算符
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
关系运算符需要注意的就是等于号是'==',这是很多人都会犯的错误。
位运算
&按位与
|按位或
^按位异或
算上前文谈及的位运算,我们的基础位运算符就全部呈现了。计算方式等同于先前讲过的,即《离散数学》课程中的与,或和异或。
值得一提的是,我们的位运算巧妙之处又可以用'^'体现出来,这个灵感来自于网络中看到的例子,十分的巧妙:
两个位的swap需要我们创建一个中间量。用于在转值的时候保存其中一个数据,但利用'^'我们可以仅用两个值就简单的结束交换的过程,不需要引入第三个量,具体原理和过程我会以注释标出在下述代码段里:
int main(){
int a=3;
int b=2;
a=a^b; //此时不需要把a的值视为1,只需要a^b即可
b=a^b; //由于b=a^b^b => b=a
a=a^b; //此时a=a^b^a => a=b
return 0;
}
实质上,这段代码利用了'^'符号运算后,在经过改值的同时蕴藏在一个变量中同时含有两个隐藏值,从而以另一种存储的形式将数据进行了巧妙的转换。
位运算是对数据整形进行运算,除去前文提及的单片机,还主要用于编写系统软件,完成汇编语言能够完成的一些功能。
逻辑与,逻辑或
&&逻辑与
|| 逻辑或
逻辑与即当左右两边的式子同时成立时,输出逻辑值为1,否则为0;
逻辑或是当左右两边至少有一个式子成立,即输出逻辑值为1,都不成立才为0 ;
需要提及一点,逻辑或的运算逻辑很特别,
逻辑运算自左向右,如果左边已经可以决定结果,那么就不会进行右边的运算例如:3>1||i++,在逻辑非语句后,i的值仍为i。这种情况也被叫做短路。
在上述所提及的操作符中,它们的优先级都相同,且结合性是自左向右。
三目运算符
即条件运算符,与for循环较为相似,基本格式如下:
条件判断?判断为真后执行的操作:判断为假后执行的操作;
/*eg:
int count = 3
count=(count>20)?count-10:count+10;
count=13
*/
它的优先级卡在了两类之间,结合性是自右向左。
赋值运算符
‘=’运算符是优先级较低的,毕竟需要最后在执行等号操作,等于号是可以与其他符号搭配使用的:
/=
除后赋值
变量/=表达式
*=
乘后赋值
变量*=表达式
%=
取模后赋值
变量%=表达式
+=
加后赋值
变量+=表达式
-=
减后赋值
变量-=表达式
<<=
左移后赋值
变量<<=表达式
>>=
右移后赋值
变量>>=表达式
&=
按位与后赋值
变量&=表达式
^=
按位异或后赋值
变量^=表达式
|=
按位或后赋值
变量|=表达式
以+=为例,i+=3的寓意为i=i+3,其他相同。
在上述所提及的操作符中,它们的优先级都相同,且结合性是自右向左。
逗号运算符
‘,’居然也是一个运算符?是的,在除部分语句的基本格式要求使用范围外,逗号运算符一般会搭配圆括号使用,而逗号运算符的作用是取最右的边值。
总结规律
结合性:除单目,赋值和条件外,其他都是左结合
优先级:单目高于双目,双目高于三目,三目高于赋值
至此,我们所介绍的操作符就全部讲完,操作符的知识还有些许小结,需要大家自己去寻找,还有些许变量类型未经过详细讲解,我们会统一作为运算一大栏的算子去放在下一篇文章中,以保证文章不会参杂过多冗杂的水分。
操作符的知识总是很枯燥,我们需要结论或口诀去反复记忆,当多个操作符聚合在一起的时候,只有熟练的理清它们之间的优先级和结合性,才能庖丁解牛,逐鹿更高的台阶。
那么,我今天的博客到此为止,感谢您认真看完了本篇小白编写的博客,以上均为本人理解,如有错误欢迎在评论区指出。
虽然基础薄弱,但今天仍是在幻想成为大佬的一天。
醉后不知天在水,满船清梦压星河