系列文章目录
速通C语言系列
速通C语言第一站 一篇博客带你初识C语言 http://t.csdn.cn/K43IN
速通C语言第二站 一篇博客带你搞定分支循环 http://t.csdn.cn/O9ISr
速通C语言第三站 一篇博客带你搞定函数 http://t.csdn.cn/vkcsU
速通C语言第四站 一篇博客带你学会数组 http://t.csdn.cn/Ol3lz
五一快乐! 感谢佬们阅读支持!
我是一个特别固执的人,我从来不会因为到了五一就不卷,如果
你们也可以像我一样,那么我觉得这件事情……
文章目录
前言
在初始C语言中,我们介绍了一些操作符,这篇博客将带大家学习初始C语言中未做介绍的操作符或对已经介绍过的操作符进行一波补充。 下面,我们就开始吧!
补充
我们先来补充一些概念
在C/C++中,我们把int、 char、double等和所有指针等这些由C/C++所提供的类型叫做内置类型,而把那些结构体等由我们自己实现的类型叫做自定义类型。
由此,我们得知编译器“认识”内置类型,而“不认识”自定义类型
编译器知道如何对内置类型操作,而不知道如何对自定义类型操作
所以在C语言阶段,操作符只能对内置类型操作。
一、各种操作符的介绍
1 位操作符& | ^
按位与 按位或 按位异或
&
两个数对应的二进制位中
两个至少一个为0--------》0
两个都为1-----------------》1
给一波例子
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
//& 按位与
int c = a & b;
printf("%d\n", c);
return 0;
}
在上面的规则下,我们得出结果
即为1
|
两个数对应的二进制位中
两个至少一个为1--------》1
两个都为0-----------------》0
给一波例子
int main()
{
int a = 3;
int b = 5;
//| 按位或
int c = a | b;
printf("%d\n", c);
return 0;
}
得出结果
即为7
^
两个数对应的二进制位中
两个不同-----------------》1
两个相同-----------------》0
给一波例子
int main()
{
int a = 3;
int b = 5;
//^按位异或
int c = a ^ b;
printf("%d\n", c);
return 0;
}
得出结果
即为6
另外,有性质
a^a=0
0^a=a
面试题
许多面试题都是以位操作符展开的,下面给出三个题玩一玩
例一:
交换a,b的值,但不能引入第三方变量。
不能引入第三方变量,就是限制我们使用之前的“给临时变量再交换"的方法。
这里给出两种方法
法一:
a=a+b; b=a-b; a=a-b;
这种方法很好理解,但是如果a,b过大,就会溢出(int有大小限制)。
法二:使用(按位异或)^
a=a^b; b=b^a; a=a^b;
这个方法有点难理解,我给大家画一波图
(成功交换)而且也不会存在溢出的问题.
例二:
判断一个数的二进制位有几个1
这个题的方法有很多,此处我们用按位与的方法,更多牛逼的方法详见我这篇速通C语言支线第一站 基础刷题 http://t.csdn.cn/kbEBq
比如给个 int a=13
让他按位与1
如果最后一位是1,得到的就是1
然后再用移位操作符+循环让他左移。
上代码
int Set(int n)
{
int i = 0;
int count = 0;
//由于一个数的二进制位有32位,所以循环32次
for (i = 0; i < 32; i++)
{
//用>>右移二进制位
if ((n >> i) & 1 == 1)
{
count++;
}
return count;
}
}
例三:
改变一个数二进制的某一位
int a=13
还是画一波图
比如要改变这个位置
将其按位与
(1<<4)
即
a=a|(1<<4);
如何再改回来?
在前面加上~(逻辑反)即可。
a=&~(1<<4);
2 对逻辑运算符的补充
&&
先给一段程序,大家来看看a,b,c,d的值各为多少
int main()
{
int i = 0;
int a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("%d %d %d %d", a, b, c, d);
return 0;
}
看似是
a=1 b=3,c=3,d=5
但运行之后
结果是 1 2 3 4 。为什么?
这里要介绍&&的一个性质了
在有很多&&的一个式子中,自左向右来看,如果出现了一个假,那后面的东西都将忽略,整个式子的值为假。
所以在这个题中,a是后置++,所以在使用时,a=0,0为假,所以整个式子的值已经为假了,后面的++b,d++就被忽略了,所以b=2,d=4.
同理可得 || 的类似性质,
在有很多 || 的一个式子中,自左向右来看,如果出现了一个真,那后面的东西都将忽略,整个式子的值为真。
我们沿用上面的例子做修改
i = a++ || ++b || d++;
a为假,b为真,所以后面的d++就不算了,所以结果为
1 3 3 4
总结:&&一遇到假,后面就不算了
|| 一遇到真,后面就不算了
3 对单目运算符的补充
sizeof
使用方式
我们直接上例子理解
例:
int a = 10;
//正常
printf("%d\n", sizeof(a));
//由于sizeof不是函数,所以可以不加括号
printf("%d\n", sizeof a);
//直接算类型
printf("%d\n", sizeof (int));
三种方式均可得出答案
sizeof内部不计算
例:
int main()
{
int a = 10;
short s = 5;
printf("%d\n", sizeof(s = a + 3));
return 0;
}
如果这波sizeof计算了,s就会整形提升为int,结果就会变成4
但是sizeof内部不计算,所以结果为s的大小,即为short的大小,即为
2
二、表达式求值
在编译时由编译程序按照一定规则自动完成,而不需人为干预。因此,在表达式中如果有不同类型的数据参与同一运算时,编译器就在编译时自动按照规定的规则将其转换为相同的数据类型。通俗来讲,就是偷偷发生的转换。
另外,后期我们学习C++时,可以用一个关键字来阻止隐式类型的转换。
整形提升
C的整形算术运算总是以缺省型类型的精度来进行的
为了获得精度,表达式的字符(char,1bit)和短整型(short,2bit)在使用前
被被转换为普通整形,这种转换成为整形提升。
简单来看,只要不超过4bit的,就要发生整形转换,因为CPU内的整形运算器,一般为4bit的int类型。
另外,整形提升的规则是 按变量的数据结构的符号位来提升的。
例:
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d\n", c);
return 0;
}
在这一个式子中,a,b为char类型,均未达到一个int的大小,所以发生整形提升
由于a,b符号位为零,所以提升时高位补零。
然后提升后的a,b做计算,结果为
但是这个结果要保存到c中,c是个char类型,只能保存8个比特位,那怎么办?
只能是将原结果截断为8个比特位
即
而打印出来,则又需要整形提升
高位为1,所以是一个负数,内存中存的是补码,而打印出来的是原码
我们需要做原码、反码、补码的转换
所以最终结果为-126。
这里我们对char 、unsigned char做一个补充
char的最高位是符号位,其大小范围为-128~127
而unsigned char最高位不是符号位,其大小范围为0~255
这两张图非常重要,希望大家牢记
.算数转换
如果某个操作符的各个操作数属于不同的类型,那么除非一个操作数转换为另一个操作数的类型,否则操作就无法进行。
我们用图的方式来给出算数转换的规则
比如int + long int,需把int 转为 long int 。
2.操作符的属性
复杂表达式求值有三个影响因素
1 操作符的优先级 两个相邻的操作符先执行哪个?
2 操作符的结合性 左结合(从左向右执行) 右结合(从右向左执行)
3 是否控制求值顺序(一般没有)
二般:如 &&,左边为假,右边就不用算了,因为整个表达式已经是假的了
具体每个操作符的优先级、结合性,这里我给到一张表,我们可以直接查
举一波例子
a+b*7
* 优先级大于 + 。所以先乘再加.
//优先级决定了运算顺序
int c=a+b+7
优先级相同,加号的结合性事左结合,所以先a+b,再加7
//结合性决定运算顺序
3 问题表达式
即使我们学习了以上知识,仍有可能算不出一些表达式的值
比如
a*b+c*d+e*f
如果按优先级来看,就是先乘,后加,顺序即为
但如果,从结合性来考虑
前两个式子算出结果后先相加,再算第三个式子,再加起来。顺序就为
再给一个例子
c+ --c
优先级上,-- 大于 +
我们设C等于3
第一种
3+(3-1)=5
第二种
先让--c算,3-1,所以原式为
(3-1)+(3-1)=4
所以我们无法确定唯一的计算路径
同样的代码,不同的平台下都可能会不同
总结
做总结,今天给大家补充了几个操作符的点以及表达式计算的规则,相较于前几篇博客,难度和重要性都有下降,大家只要理解并记住即可。水平有限,还请各位大佬指正。如果觉得对你有帮助的话,还请三连关注一波。希望大家都能拿到心仪的offer哦。