我们该如何对付花里胡哨的运算符优先级(C)
写在前面:这里是小王成长日志,一名普通在校大学生,想成学习之余将自己的学习笔记分享出来,记录自己的成长轨迹,帮助可能需要的人,平时博客内容主要是一些学习笔记,项目实战笔记,一些技术的探究和自己的一些思考。欢迎大家关注,你们的每一个评论点赞关注我都会仔仔细细去看的。有任何问题欢迎交流,我会尽我所能帮助大家的,共创CSDN美好环境。
一般来说,运算符优先级这种东西不应该去强行记忆,因为在自己不确定的时候用括号来为表达式强行指定顺序就完事了,方便简单不伤脑,而且在不同的语言中优先级也可能不同,用多了自然就熟了,但是!
直到看到一些题目,我才知道也许我们能够控制自己,但是不能控制别人写出那种毁天灭地的代码,而且!老师也喜欢出那种花里胡哨的题目,日常掉发的程序猿继续落泪~
文章目录
1.速查表
供速查用,会不会都请先大致浏览一遍再看下面的。下面是一个文档,内含C语言常用转义字符、ASCII、优先级的对照表。(本来想直接上传CSDN的,奈何审批太慢)
…发出来前几秒,有提示我审核通过了 点链接下载,不需要积分
链接:https://share.weiyun.com/5695tZw 密码:7ytpbm
优先级 |
运算符 |
名称或含义 |
使用形式 |
结合方向 |
说明 |
---|---|---|---|---|---|
1 |
[] |
数组下标 |
数组名[常量表达式] |
左到右 |
|
() |
圆括号 |
(表达式)/函数名(形参表) |
|||
. |
成员选择(对象) |
对象.成员名 |
|||
-> |
成员选择(指针) |
对象指针->成员名 |
|||
2 |
- |
负号运算符 |
-表达式 |
右到左 |
单目运算符 |
(类型) |
强制类型转换 |
(数据类型)表达式 |
|||
++ |
自增运算符 |
++变量名/变量名++ |
单目运算符 |
||
-- |
自减运算符 |
--变量名/变量名-- |
单目运算符 |
||
* |
取值运算符 |
*指针变量 |
单目运算符 |
||
& |
取地址运算符 |
&变量名 |
单目运算符 |
||
! |
逻辑非运算符 |
!表达式 |
单目运算符 |
||
~ |
按位取反运算符 |
~表达式 |
单目运算符 |
||
sizeof |
长度运算符 |
sizeof(表达式) |
|||
3 |
/ |
除 |
表达式/表达式 |
左到右 |
双目运算符 |
* |
乘 |
表达式*表达式 |
双目运算符 |
||
% |
余数(取模) |
整型表达式/整型表达式 |
双目运算符 |
||
4 |
+ |
加 |
表达式+表达式 |
左到右 |
双目运算符 |
- |
减 |
表达式-表达式 |
双目运算符 |
||
5 |
<< |
左移 |
变量<<表达式 |
左到右 |
双目运算符 |
>> |
右移 |
变量>>表达式 |
双目运算符 |
||
6 |
> |
大于 |
表达式>表达式 |
左到右 |
双目运算符 |
>= |
大于等于 |
表达式>=表达式 |
双目运算符 |
||
< |
小于 |
表达式<表达式 |
双目运算符 |
||
<= |
小于等于 |
表达式<=表达式 |
双目运算符 |
||
7 |
== |
等于 |
表达式==表达式 |
左到右 |
双目运算符 |
!= |
不等于 |
表达式!= 表达式 |
双目运算符 |
||
8 |
& |
按位与 |
表达式&表达式 |
左到右 |
双目运算符 |
9 |
^ |
按位异或 |
表达式^表达式 |
左到右 |
双目运算符 |
10 |
| |
按位或 |
表达式|表达式 |
左到右 |
双目运算符 |
11 |
&& |
逻辑与 |
表达式&&表达式 |
左到右 |
双目运算符 |
12 |
|| |
逻辑或 |
表达式||表达式 |
左到右 |
双目运算符 |
13 |
?: |
条件运算符 |
表达式1? 表达式2: 表达式3 |
右到左 |
三目运算符 |
14 |
= |
赋值运算符 |
变量=表达式 |
右到左 |
|
/= |
除后赋值 |
变量/=表达式 |
|||
*= |
乘后赋值 |
变量*=表达式 |
|||
%= |
取模后赋值 |
变量%=表达式 |
|||
+= |
加后赋值 |
变量+=表达式 |
|||
-= |
减后赋值 |
变量-=表达式 |
|||
<<= |
左移后赋值 |
变量<<=表达式 |
|||
>>= |
右移后赋值 |
变量>>=表达式 |
|||
&= |
按位与后赋值 |
变量&=表达式 |
|||
^= |
按位异或后赋值 |
变量^=表达式 |
|||
|= |
按位或后赋值 |
变量|=表达式 |
|||
15 |
, |
逗号运算符 |
表达式,表达式,… |
左到右 |
从左向右顺序运算 |
2.记忆方法
开始记忆之前我们先来看一下一些表中涉及到的概念:
什么是目?
所谓"目",也可以称之为元,那么我们再来看看,单元(一元)运算符,双元运算符,三元运算符,再看看例如看看下面几个表达式,有没有点感觉?
a++;// ++ 单目 &b;//& 单目 c - d;//- 双目 e > f;//> 双目 (1 > 2) ? a : b,//?: 三目
单目运算符, 一些只需要一个操作数的运算符称为一元运算符(或单目运算符),以此类推,双目运算符有需要两个操作数数才能进行运算.三元则需要三个(参考百度百科)
C语言中大部分都是双目运算符,小部分是单目的,三目运算符只有一个,就是条件运算符 ?:
结合方向是什么?
在上面的表里,我们还能看到特殊的一列,就是结合方向,这一列指得是当运算符有优先级相同(同级)时的运算顺序.
巧记方法
其实我也不想记,想在使用中熟悉,想着加括号就好,但是牢不住老师太猛啊,还是乖乖记一下吧:
- 1,记住总表的规律
C语言中大多数运算符的结合性都是从左往右,只有三个运算符是从右往左的。一个是单目运算符,另一个是三目运算符,还有一个就是双目运算符中的赋值运算符
=
。 - 双目运算符中只有赋值运算符的结合性是从右往左的,其他的都是从左往右。
- C语言中有且只有一个三目运算符。
- 逗号运算符的优先级最低,要记住。
- 此外要记住,对于优先级:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符。逻辑运算符中“逻辑非 !”除外。
2.背一段顺口溜
这是我在网上找的一段顺口溜,背下来应该也是有用的
醋坛酸味灌
味落跳福豆
共44个运算符:
醋 | 初等,4个:()[]->指向结构体成员.结构体成员 |
坛 | 单目,9个:!~+±–负号(类型)*指针&取地址sizeof长度 |
酸 | 算术,5个:*/%±减 |
味 | 位移,2个:<<>> |
灌 | 关系,6个:<<=>>===等于!=不等于 |
味 | 位逻,3个:&按位与^按位异或|按位或 |
落 | 逻辑,2个:&&逻辑与||逻辑或 |
跳 | 条件,1个,三目:?: |
福 | 赋值,11个:=+=-=*=/=%=>>=<<=&=^=|= |
豆 | 逗号,1个:, |
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
参考:
3.一起看看运算符优先级的一些题目
1. C语言混乱代码大赛-尝试理解一下下面这段代码
#include <stdio.h> char *a; main(int t,int _,char* a){return!0<t?t<3?main(-79,-13,a+main(-87,1-_, main(-86,0,a+1)+a)):1,t<_?main(t+1,_,a):3,main(-94,-27+t,a)&&t==2?_<13? main(2,_+1,"%s %d %d\n"):9:16:t<0?t<-72?main(_,t, "@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# ){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c ;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/") :t<-50?_==*a?putchar(31[a]):main(-65,_,a+1):main((*a=='/')+t,_,a+1) :0<t?main(2,2,"%s"):*a=='/'||main(0,main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}
能力有限,我就不班门弄斧了,而且这个远远不止于运算符优先级,感兴趣的同学可以点上面的超链接去看看
2. *p++自增p还是p所指向的变量?
在这一题中,根据我们的理解,* 的优先级是要低于 自增符++的,所以 *p++ 实际上和 *(p++) 等价,它自增p并且返回p自增之前所指向的值。
如果我们想要自增p所指向的值则需要写成 (*p)++;
看代码:
int *p = NULL; int arr[2] = {1, 10}; p = arr; printf("*p++ = %d\n",*p++);//1 printf("*p = %d\n",*p);//10 p = arr; printf("(*p)++ = %d\n",(*p)++);//1 printf("*p = %d\n",*p);//2
3. 试着理解a+++++b
在C中,写成这样也是没有意义的。词汇分析的规则规定,在一个简单的从左到右扫描中的每个点,最长的记号被划分,不管这样出来的记号序列是否有意义。问题中的片段被解释为
a ++ ++ +
在语法上说这是个不合法的表达式
经提醒 在JAVA中这样写是合法的,注意区分
看代码
int a,b; a=1; b=2; printf("a+++++b = %d",a+++++b); /**************运行结果 test.c: In function 'main': test.c:9:30: error: lvalue required as increment operand printf("a+++++b = %d",a+++++b); **************/
4. k = j>i && 8==i;
岔看到这个表达式的时候会不会有点头晕,因为我们日常都会在不明确的地方加上括号,例如
( k = j )&&( 8 == i )
但是在这个表达式中没有任何括号给我们提示,并且涉及到了四种运算符,其优先级都需要我们自己去考虑。
首先速查这四种运算符的优先级:
赋值运算符优先级最低,其次&&AND运算符,== 和 > 虽然都是双目运算符,但是== 优先级低于 > 运算符。
所以上式等同于
(k = (j > i)) && (8 == i)看代码:
int k, j, i; k = 1; j = 2; i = 8; printf("%d\n",j > i);//0 printf("%d\n",k = (j > i));//0 printf("%d\n",8 == i);//1 printf("(k = (j > i)) && (8 == i) = %d\n", (k = (j > i)) && (8 == i));//0 printf("k = j > i && 8 == i = %d", k = j > i && 8 == i);//0
4.参考
- 详见原文超链接
5.以往文章推荐
都看到这里了,各位哥哥姐姐叔叔阿姨给小王点个赞 关个注 留个言吧,和小王一起成长吧,你们的关注是对我最大的支持。
如果以上内容有任何不准确或遗漏之处,或者你有更好的意见,就在下面留个言让我知道吧-我会尽我所能来回答。
北海以北没有小王 原创文章 32获赞 861访问量 3万+ 关注 私信- 如何对付电脑对我们皮肤的伤害
- 美国如何对付假钞,我们该学习学习
- 如何使用GitHub管理我们的源码
- 如何让我们的PHP在Jexus中跑起来
- 如何对付网络爬虫 - JavaEye和网络爬虫斗争之路
- 如何专心睡眠:当我们的思维停不下来的时候
- 物联网将改变未来:科技如何引领我们未来的生活?
- 我们如何从VC++开始“编程”?
- 在闲鱼,我们如何用Dart做高效后端开发?
- 微信时代我们如何运营——读《微信运营手册》有感
- 如何对付开会中的意外情况
- 如何把我们培养成销售精英
- 经验之谈—如何避免第三方框架过分的污染我们的项目
- apiexample.c例子教我们如何利用FFMPEG库中的API函数来编写自己的编解码程序
- java-day15api的概述: 就是java替我们写好的一些类,他封装了一些功能,我们仅仅只需要知道如何使用即可
- 系统是如何根据我们给的路径而找到并读取文件的呢?
- 大数据:一场改变我们如何生活、工作和思考的革命(更多,凌乱,足够好)
- 我们项目组单元测试该如何开展
- 我们究竟应该如何学习编程
- 我们究竟该如何与AI相处?从一个创业故事讲起 | 观点