【C语言操作符详解(一)】--进制转换,原反补码,移位操作符,位操作符,逗号表达式,下标访问及函数调用操作符
目录
一.操作符的分类
二.二进制和进制转换
2.1--2进制转10进制
编辑 2.1.1--10进制转2进制数字
2.2--2进制转8进制和16进制
2.2.1--2进制转8进制
2.2.2--2进制转16进制
三.原码,反码,补码
四.移位操作符
4.1--左移操作符
4.2--右移操作符
五.位操作符:&,|,^,~
5.1--位操作符的理解与使用
5.2--相关练习
5.2.1--练习1:不能创建临时变量(第三个变量),实现两个整数的交换。
5.2.2--练习2:编写代码实现:求一个整数存储在内存中的二进制中1的个数
5.2.3--练习3:二进制位置0或者置1
六.逗号表达式,下标访问 [],函数调用 ()
6.1--逗号表达式
6.2--[] 下标引用操作符
6.3--() 函数调用操作符
前言:上篇文章我们学习了函数递归的相关知识,今天我们将继续操作符的详解学习的第一部分,让大家对于c语言的操作符产生一些新的认识和想法。
一.操作符的分类
1.算术操作符:+ , - , * , / , %
2.移位操作符:<< , >>
3.位操作符:&, | ,^
4.赋值运算符:= , += ,- = ,*= ,/= ,%= ,<<= ,>>= , &= , |= ,^=
5.单目操作符:!,++ ,- - ,& ,* ,+(正),-(负) ,~ ,sizeof ,(类型)
6.关系操作符:> ,>= ,< ,<= ,== ,!=
7.逻辑操作符:&& ,|| ,!
8.条件操作符:exp1?exp2:exp3
9.逗号表达式:,
10.下标引用:【】
11.函数调用:()
12.结构成员访问:. , ->
上述的操作符中,有部分在之前的学习中有提到过,今天继续介绍一部分,其中有部分操作符和二进制有关系,我们先来学习一下二进制和进制转换的相关知识;
二.二进制和进制转换
2.1--2进制转10进制
--其实10进制的123表示的值是一百二十三,为什么是个值呢?其实10进制的每一位都是有权重的,进制的数字从右向左是个位,十位,百位……,分别每一位的权重是10^0,10^1,10^3;
如下图:
2进制和10进制是类似的,只不过2进制的每一位的权重,从右向左是:2^0,2^1,2^2……
如果是2机制的1101,该怎么理解呢?
2.1.1--10进制转2进制数字
简单的10进制数字可以直接通过凑的方法来转2进制;
2.2--2进制转8进制和16进制
2.2.1--2进制转8进制
--8进制的每一位是0~7的,0~7的数字,各自写成2进制,最多有3个2进制位就足够了,比如7的二进制是111,所以2进制转8进制的时候,从2进制序中右边低位开始向左每3个二进制位会换算一个8进制位,剩余不够3个2进制位的直接换算。
如:2进制的01101011,换成8进制:0153,8进制表示的时候前面加0;0开头的数字,会被当作8进制。
2.2.2--2进制转16进制
--16进制的数字每一位是0~9,a~f的,0~9,a~f的数字,各自写成2进制,最多有4个二进制位就足够了。比如f的二进制是1111,所以在2进制转16进制的时候,从2进制序列中右边低位开始向左每4个2进制位会换算一个16进制位,剩余不够4个2进制位的直接换算。
如:2进制的01101011,换成16进制:0x6b,16进制表示的时候前面加0x。
三.原码,反码,补码
--整数2进制的表示方法有三种,即原码,反码和补码(32位)
有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,最高位的1位是被当做符号位的,剩余的都是数值位,符号位都是用0表示正,用1表示负。
正整数的原,反,补码都相同。
负整数的三种表示方法各不相同,变换方式如下。
原码:直接将数值按正负数的形式翻译成二进制得到的就是原码。
反码:原码的符号位不变,其他位次按位取反就可以得到反码。
补码:反码+1就得到补码。
补码反过来得到原码也是可以使用:取反,+1的操作。
对于整型来说:数据存放内存中其实存放的是补码。
这是为什么呢?
--在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
四.移位操作符
<< 左移操作符
>> 右移操作符
注意:移位操作符的操作数只能是整数
4.1--左移操作符
--移位规则:左边抛弃,右边补0;
int num=10;左移一位演示
4.2--右移操作符
1.逻辑右移:左边用0填充,右边丢弃
2.算术右移:左边用原该值的符号位填充,右边丢弃
--是逻辑右移还是算术右移取决于编译器,VS2022中采用的是算术右移。
int num=-1;逻辑右移一位演示
int num=-1;算术右移一位演示
注意:对于移位运算符,不要移动负数位,这个是标准没定义的。
五.位操作符:&,|,^,~
5.1--位操作符的理解与使用
位操作符有:
& //按位与
| //按位或
^ //按位异或
~ //按位取反
注意:他们的操作数必须是整数。
我们可以通过一串代码直观了解一下这几个位操作符,注意看注释,来理解是如何使用的。
#include <stdio.h>
int main()
{int num1 = -3;int num2 = 5;
// &--按位与--对应的二进制位进行与运算,只要有0则为0,两个同时为1,才为1printf("%d\n", num1 & num2);
// |--按位或--对应的二进制位进行或运算,只要有1则为1,两个同时为0,才为0printf("%d\n", num1 | num2);
// ^--按位异或--对应的二进制位相同为0,相异为1printf("%d\n", num1 ^ num2);
// ~--按位取反--二进制位0变为1,1变为0printf("%d\n", ~0);return 0;
}
5.2--相关练习
5.2.1--练习1:不能创建临时变量(第三个变量),实现两个整数的交换。
int main()
{int a = 0;int b = 0;printf("请输入两个整数:");scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);a = a ^ b;// a'=a^b;b = b ^ a;// b=b^a'=b^a^b=a;a = a ^ b;// a=a'^b=a^b^a=b;printf("交换后:a=%d b=%d\n", a, b);return 0;
}
在这里补充两个重要结论:
a ^ a = 0;
a ^ 0 = a;
//且异或支持交换律;
//如:3 ^ 6 ^ 6 = 3
// 6 ^ 3 ^ 6 = 3
5.2.2--练习2:编写代码实现:求一个整数存储在内存中的二进制中1的个数
int count_bits1_of_n(int n)
{//int count = 0;//for (int i = 0;i < 32;i++)//{// if(((n >> i) & 1)==1)// count++;//}//return count;//优化方案int count = 0;while (n){n = n & (n - 1);
//用一次这个公式就相当于将一个1变为0,即去掉一个1,当n为0时,1全部去掉,且刚好循环结束count++;}
}int main()
{int n = 0;scanf("%d", &n);int ret = count_bits1_of_n(n);printf("%d", ret);return 0;
}
注意:n=n&(n-1)这个公式的用法在这里很重要。
5.2.3--练习3:二进制位置0或者置1
编写代码将13二进制序列的第五位修改为1,然后再改回0;
int main()
{int a = 13;a = a | (1 << 4);printf("a=%d\n", a);a &= ~(1 << 4);printf("a=%d\n", a);return 0;
}
六.逗号表达式,下标访问 [],函数调用 ()
6.1--逗号表达式
exp1, exp2, exp3, …expN
逗号表达式,就是用逗号隔开的多个表达式。从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?--c是13;//代码2
if(a = b + 1,c = a / 2,d > 0)//代码3
a = get_val();
count_val(a);
while (a > 0)
{//业务处理//...a = get_val();count_val(a);
}如果使⽤逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{//业务处理
}
6.2--[] 下标引用操作符
--操作数:一个数值名 + 一个索引值(下标)
int arr[10]={0};//创建数组
arr[9] = 10;//运⽤下标引⽤操作符。
[ ]的两个操作数是arr和9。
6.3--() 函数调用操作符
int Add(int x,int y)
{return x + y;
}int main()
{printf("hehe");//()是函数调用操作符int r = Add(3,5);//()是函数调用操作符// ()也是有操作数:函数名和参数都是()的操作数//()最少有一个操作数,就是函数名本身return 0;
}
结语:操作符详解的第一部分就到此结束了,在下一篇文章中我将继续为大家分享操作符详解的一些其他知识点,感谢大家的支持!