1.位操作符
注意:对于位操作符,他们的操作数必须是整数。
1.按位“异或”运算(^)
按位“异或”运算符是双目运算符,其功能是将参与运算的两数的对应二进制位相“异或”。
运算规则:位置相同结果为0,相异为1。
运算特点:a:0异或任何数 == 任何数 b: 1异或任何数 == 任何数取反 c: 任何数异或自己 == 把自己置0
支持交换律:10 ^ 20 ^ 10 == 10 ^ 10 ^ 20 == 0 ^ 20 == 20
应用举例:
(1):实现两个值的交换,而不必 使用临时变量。这种方法因为不会产生进位,所以不会溢出,建议采用!!!
void Swap(int*xp, int*yp){
*xp ^= *yp;
*yp ^= *xp;
*xp ^= *yp;
}
(2):快速判断两个值是否相等
return ((a ^ b) == 0)
2.按位或(|)
运算规则:每一位上,有1为1,同0 为0.
注:自己和自己按位或,得其本身。
3.按位与(&)
运算规则:每一位上,同为1时为1,否则为0.
注:任意一个数和-1按位与,得其本身。
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清0,保留低八位,可作 a & 255运算(255的二进制数为00000000…0011111111)。
编写代码实现:求一个整数存储在内存中的二进制中的1的个数。
方法一:(缺陷:不能计算负数!)
#include<stdio.h>
#pragma warning(disable:4996)
int main(){
int num = 10;
int count = 0;//计数
while (num){
if (num % 2 == 1){//括号里的条件用于检测最低比特位
count++;
}
num = num / 2;
}
printf("二进制中1的个数 = %d\n", count);
system("pause");
return 0;
}
方法二:(缺陷:因为结果为 32,这里必须循环32次)
#include<stdio.h>
#pragma warning(disable:4996)
int main(){
int num = -1;
int i = 0;
int count = 0;//计数
for (i = 0; i < 32; i++){
if (((num >> i) & 1) == 1){
count++;
}
}
printf("二进制中1的个数 = %d\n", count);
system("pause");
return 0;
}
方法三:(一次消去一个二进制位中的1,效率高)
#include<stdio.h>
#pragma warning(disable:4996)
int main(){
int num = -1;
int count = 0;//奇数
while (num){
count++;
num = num&(num - 1);
}
printf("二进制中1的个数 = %d\n", count);
system("pause");
return 0;
}
2.移位操作符
1.左移操作符
移位规则:最高位丢弃,最低位补0.(左移操作符本身与数据正负性无关。)
2.右移操作符
移位规则:1.逻辑移位(对应无符号数)左边用0补充,右边丢弃 2.算数移位(对应有符号数)左边用原该值的符号位填充(正数补0,负数补1),右边丢弃
正数:15 >>>> 2
首先转化为二进制,15的二进制为0000 1111;将二进制数向右移两位,高位补0,得到 0000 0011;最后将二进制数转化为十进制数,0000 0011转化为3
所以,15 >>>>2 = 3
负数:因为负数的符号位(最高位)为1,而无符号右移要在最高位补0,所以32位二进制要写全。带符号右移(>>),高位补的是符号位,前24位都是1
eg:-15>>>>2
首先转化为二进制,-15的二进制为1111 1111 1111 1111 1111 1111 1111 0001;将二进制数向右移两位,高位补0,得到0011 1111 1111 1111 1111 1111 1111 1100
最后将二进制数转化为十进制数,0011 1111 1111 1111 1111 1111 1111 1100转化为十进制数为1,073,741,820
3.逻辑操作符
1.逻辑与(&&)
即为and,当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false.(C语言中,0为假,非0为真)
比如:12 && 23 的结果就是1,12&& -1 的结果是1,123&& 0 的结果是0
&&还具有短路的功能,即如果第一个表达式为假,则不计算第二个表达式,例如,if(0 && printf(“hello”));后面的表达式不会执行!!
2.逻辑或(||)
逻辑或,当两个条件中有任一个条件满足,“逻辑或”的运算结果就为真
eg:12 || 1 = 1,12 || 0 = 1,0 || 0 = 0
当第一个表达式为真,则不计算第二个表达式!!!
360经典面试题
#include<stdio.h>
#pragma warning(disable:4996)
int main(){
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;//a = 0,不会进行第一个逻辑与后的操作
//i = a++ || ++b || d++;第二个逻辑或后的操作不会进行
printf("a = %d\n b = %d\n c = %d\n d = %d\n i = %d\n", a, b, c, d, i);//1 2 3 4 0
//printf("a = %d\n b = %d\n c = %d\n d = %d\n i = %d\n", a, b, c, d, i);//1 3 3 4 1
system("pause");
return 0;
}
4.三元运算符
运算规则:exp1 ? exp2 : exp3 第一个是表达式,剩余两个是值,条件表达式为真时,取第一个值,为假时,取第二个值。
注意点:如果两个定义了数据类型的变量,那么返回的结果就是范围大(精度高)的类型。
5.逗号表达式
(exp1,exp2,exp3,….expN)
注意点:1.从左向右依次执行;2.整个表达式的结果是最后一个表达式的结果。3.逗号表达式的优先级在所有运算符中最低 。
6.复杂表达式计算的问题
a*b + c*d + e*f
注释1:代码在计算的时候,由于 * 比 + 的优先级高,但是优先级并不能决定第三个 * 比第一个 + 执行早。
所以表达式的计算机顺序就可能是:
a * b
c * d
a*b + c*d
e * f
a*b + c*d + e*f
//或者:
a * b
c * d
e * f
a*b + c*d
a*b + c*d + e*f
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i)+(++i)+(++i);
printf("ret = %d\n", ret);
return 0;
}
注释:这段代码中的第一个 + 在执行的时候,第三个 ++ 是否执行,这个是不确定的,因为依靠操作符的优先级和结合性是无法决定第一个 + 和第三个前置 ++ 的先后顺序。
总结:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/110988.html