C语言操作符详解(坑点+重难点+优先级结合性总结)

✨前言✨ 

        这个系列作为【全网最强】的续作,在内容上不会只是走马灯式的浏览知识点,而会对各个知识点进行精讲精析,达到真正熟练的地步。虽然说博主学习C语言不过两个多月,但也熟知重难点和易错点,会和大家一起分享学习。关注博主🍻,在学习C语言的路上结伴前行吧。

[有问题欢迎留言讨论,作者尽力帮忙]✨


目录

一、优先级和结合性

二、 算数运算符

三、关系运算符

四、逻辑运算符

五、位操作运算符

六、赋值运算符

七、条件运算符

八、求字节数运算符

九、逗号运算符

十、强制类型转换运算符

十一、词法运算中的“大嘴法”

十二、优先级与结合性总结

十三、后记


 一、优先级和结合性

优先级:优先级的高低决定运算的优先顺序。如最常见的加和乘,3+2*5中乘法优先级高

结合性:C语言中各运算符的结合性分为两种,即左结合性(自左至右)和右结合性(自右至左)。结合性指的是编译器解释的顺序。如赋值操作符的结合性为自右向左,a=b=c实际将c赋值给b,再将b赋值给a,从右往左解释

(操作符也叫运算符) 

二、 算数运算符

<第一组>    +   -   *(乘) /(除)   %(取余) 

解释:+ - * /详细很好理解,解释一下%。取余表示取余数,如30%11=8,而30/11=2。

 注意点: 

①除号两边数据类型不同时会发生类型转。

举例:如1/2=0,因为除号两边都是整形,所以结果也是整形,1除2等于0余1。1/2.0,除号一边是整数,另一边是浮点数,类型不同,int型转化为double型,因此结果也是浮点数,所以答案是0.5。

自动类型转化原则:将参与运算的操作数转换成其中占用内存大的类型,防止数据丢失

 

 ②取余两边必须是整型,不能出现浮点数

 

 <第二组> ++(自增)    --(自减)

解释:++等价于a=a+1                  --等价于a=a-1

注意点 :

①前置++与后置++问题

前置++,先自增后使用;后置加加,先使用后加加(--同理)

过程分析:为b赋值时,++在a后后置加加,所以现将a的值赋值给b,所以b的值为5,为b赋值后a自增1变成6。为c赋值时,++在a前为前置加加,所以先将a自增再赋值给c,a自增后值为7,所以c的值为7。

为什么将上面的算数运算符分成一二组呢,因为这两组的优先级和结合性不同(在最后总结)

三、关系运算符

<第一组>   >  <  <=  >=  <=

<第二组>   ==(相等)     !=(不相等)

(为什么分成两组呢,两组的优先级不同,最后有总结)

注意点:

①大于等于中>与=之间不要留有空格,否则不会被识别为>=,其他同理

②注意:==与!=的优先级低于第一组的关系运算符

 举例:if(10>=5 == 4<=3)

>=和<=的优先级高于==,所以最后计算==

10>=5为真,整体的值为1;4<=3为假,整体的值为0。1==0为假,所以if语句不执行

③⭐易错点:注意别把==写成=。

#include<stdio.h>
int main()
{
	for (int k = -1; k = 1; k++)
	{
		printf("*****\n");
	}
	return 0;
}

 分析:写成k=1,而不是k==1,则每次不是进行判断而是将k赋值成1,1表示真,循环还会继续,所以程序的结果是死循环。在设计程序时要特别小心这种错误。 

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	if (a <= b <= c)
	{
		printf("haha");
	}
	return 0;
}

④所有表达式都有值。这里if里的逻辑是:a<=b为真,所以a<=b的值为1。1<=c成立,所以if语句执行。注意这里并不是字面看来的判断是不是a<=b<=c。

 四、逻辑运算符

<第一组>   !  (逻辑非)

<第二组>   && (逻辑与)

<第三组>   ||    (逻辑或)

(自上往下优先级降低)

解释:

1.逻辑与:两边都为真整体才为真。如 if(1>0 && 8 >9)左边为真,右边为假,整体为假。

2.逻辑或:两边只要有真整体就位真。如上面的例子用 || if语句会执行

3.逻辑假:真变假,假变真。在vs编译器下,真用1表示,假用0表示

                如 !1=0     !6=0     !0=1

 注意点:

①逻辑短路⭐:对于&&,只要一边为0,就可以确定整体的值为0,其他的值就不会再运算。对于||,只要一边为1,就可以确定整体的值为1,其他的值就不会再运算。

【总结】只在需要时对右边求值

②注意别把&&写成&,现在分析三种可能造成 &&写成 &程序“没错的原因” 

考虑以下代码,其功能是查询表中一个特定元素。

int i = 0;
while (i < tabsize && tab[i] != x)
{
	i++;
}

现分析将&&替换成&仍然能"正常工作"的原因。

原因一:只要xy的值都限制在0~1,x&&y和x&y的结果始终相同。

原因二:数组结尾之后的下一个元素,只要不改变他的值而仅仅是读取,没有什么大的危害;并且不同与&&的“逻辑短路”,&要求两边都要被求值,所以会查看tab数组结尾的后一元素(即使不存在)

(&&替换成&问题摘录于博主以前的博客,C经典书籍笔记——C陷阱与缺陷③(语意陷阱)) 

 验证优先级

上面提到优先级 && > ! > ||,我们设计程序来验证

//验证!优先级高于&&
int main()
{
	int a = 0;
	int b = 1;
	if (!a && b)
	{
		printf("haha");
	}
	return 0;
}

//验证!优先级高于||
int main()
{
	int a = 0;
	int b = 0;
	if (!a || b)
	{
		printf("%d",a);
	}
}

五、位操作运算符

<第一组>  <<(左移)   >>(右移)

<第二组>  ~(位非)   ^(位异或)   &(位与)   |(位或) 

【优先级都不同,这里不重要,所以在最后总结】

解释:位操作符是对二进制位的补码进行操作的,这里涉及数据存储的原码反码补码。原反补不是这里的重点,之后作者也会发文总结,若有不大会的可以参考这篇博客 链接

功能:

①左移:左移位将第一操作数的每一位向左平移第二操作数指定的位数(如-1<<2表示将-1的二进制位每一位向左一两位),右边空位补0,左边移出去的丢弃。

(先以-1左移1位为例图解,-1的补码为  11111111 11111111 11111111 11111111)

 ②右移:右移位将第一操作数的每一位向右平移第二操作数指定的位数,右边丢弃,左边空                 位补值。左边补值有两种情况。

                1.有符号数——符号位补符号值

                2.无符号数——补0

(先以1右移1位为例图解,1的补码为  00000000 00000000 00000000 00000001)

 ③位非:按位取反

④位与:对应二进制有0出0,全1出1

⑤位或:对饮二进制位有1出1,全0出0

⑥位异或:对应二进制位上数字相同出0,不同出1

应用: 

①用位操作符进行二进制有关的操作极其方便

例一:求一个整数存储在内存中的二进制中1的个数

方法:1.利用%2和/2每次计算一个数字当前二进制位最后一位是0还是1

           【缺陷】不能统计负数,局限性很大

           2.利用 &1,&10,&100……判断每一位二进制最后一位是1还是。100等用1<<2获取

             (不是100而是二进0制的100)

           【缺陷】运算次数过多

           3.最优解:a & (a-1),每进行一次就可以使原数字二进制少一个1,计数操作多少次使                原数字变成0,即可得出二进制中1的个数

            【理解】每次a-1只会改变二进制中最后一位的1,使原来的  10 变成  01,其他不                   变,&操作自然会使原二进制少一个1

//方法一:
int main()
{
	int n = 0;
	int count = 0;
	scanf("%d",&n);
	while (n)
	{
		count += n % 2;
		n /= 2;
	}
	printf("二进制序列中1的个数为:%d",count);
	return 0;
}
//方法二
int main()
{
	int n = 0;
	int count = 0;
	scanf("%d",&n);
	for (int i = 0; i < 32; i++)
	{
		if (n & 1 << i)
			count++;
	}
	printf("二进制序列中1的个数为:%d",count);

	return 0;
}
//方法三
int main()
{
	int n = 0;
	int count = 0;;
	scanf("%d",&n);
	while (n)
	{
		count++;
		n = n & (n - 1);
	}
	printf("二进制序列中1的个数为:%d",count);

	return 0;
}

②不使用变量使得两数交换(代码如下)

举个例子就可以理解。可以这样形象记忆a^b是一个宝盒,tmp^a相当于把a作为钥匙打开,就获得了b。但要强调的是这样的代码可读性不佳,最好的还是用三个变量。

int main()
{
	int a = 1;
	int b = 10;
	int tmp = 0;
	tmp = a ^ b;
	a = tmp ^ a;
	b = tmp ^ b;
	return 0;
}

 六、赋值运算符

<简单赋值符> =

<复合算术赋值符>  +=    -=    *=    /=    %=

<复合位运算赋值符>  &=   |=   ^=   >>=   <<=

(三种赋值运算符的优先级都相同)

符合操作符如a*=b等价于a=a*b,只是缩写罢了,注意理解。其他以此类推 

注意点 

赋值运算符的优先级是所有双目操作符中最低的,使用时尤其要注意是否要加括号

练习题: 打印的结果是什么 

#include<stdio.h>
int main()
{
	int a = 3, b = 5;
	int n = 2;
	int m;
	(m = a <= 3) && a + b < 8;
	printf("%d\n", n += n -= n * n);
	printf("%d\n", n += n -= n *= n);
	printf("%d",m );
	return 0;
}

七、条件运算符

<第一组>  ?:

(唯一的三目操作符)

作用:

所有表达式都有一个值,包括条件运算符。如果第一个子表达式为真,则条件表达式的值为第二个子表达式的值,否则它就是第三个子表达式的值。

int main()
{
	int a = 10;
	int b = 1;
	int max = 0;
	max = a > b ? a : b;
	return 0;
}

八、求字节数运算符

想必大家对sizeof都很熟悉了,这里就不赘述了。

注意:sizeof不是函数,而是操作符

九、逗号运算符

作用

 逗号表达式的值是最后一个表达式的值。注意使用时要加括号

int main()
{
	int a = 0;
	int b = 0;
	int c = (a + 10, b = a + 10, b + 10);//最后把b+10的值附给c
	printf("%d",c);
}

有时候要小心,不经意间就会错。如下面的二维数组实际只有两个元素

#include <stdio.h>
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( "%d", p[0]);
 return 0;
}

 十、强制类型转换运算符

想必大家对()也都很熟悉了,这里就不赘述了。只是注意()里的是类型而不是变量

int main()
{
	int a = 1;
	int b = 2;
	float tmp = 0.0;
	tmp = (float)a / b;
	printf("%f",tmp);
	return 0;
}

十一、词法运算中的“大嘴法”

思考

编译器对连续输入的符号是看成整体还是分别处理

如a/*b,是看成a/ (*b)还是把/*以注释符看待

原则 :大嘴法(也叫贪心法)

一个符号应该尽可能包含更多的字符。即在输入一个可能成为符号的字符后继续读入下一个字符,判断两个字符组成的字符串能否组成一个符号,重复上述过程,直至不能组成一个可能的符号。

练习: a+++++b的含义什么                                     【原来的解释有误,现纠正】

分析:根据贪心法,++组合后再一次++最后以为((a++)++))+b。然而这个式子在语法上是错误的,因为a++的结果不能作为左值,因此编译器实际不会接受a++后的++,也就会语法报错。在编程实践中的建议就是,尽量避免使用类似的结构

 十二、优先级与结合性总结

关于优先级的记忆方法,博主之前做过总结,大家可以参考   C经典书籍笔记——C陷阱与缺陷②(语法陷阱之优先级)

十三、后记

【C语言知识精讲②】出炉啦    【C语言知识精讲②】static修饰局部变量,全局变量,函数区别

这四个没有提到的运算符会在之后关于数组,指针,结构体的专题里细讲。这里先不提了。

还有哦提醒一下,define不是运算符,而是预处理指令。

指针运算符:*和&

分量运算符:. ->

下标运算符:[ ]

函数调用运算符:()

关于C语言操作符博主就不再总结了,因为之前看到过一篇不错的博文,大家可以看看

详解C语言操作符(史上最全的重点总结!全在这里!)

  • 136
    点赞
  • 297
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罅隙`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值