一.复习
1.数值分为整数和小数,整数分为有符号整数和无符号整数。(有符号整数分为正数和负数)
2.原码取反为反码,反码+1为补码
二.操作符详解
1.移位操作符(参与运算的都是二进制数字的补码形式)
(1) 移位操作符分为左移操作符<<和右移操作符>>
(2) 规则:移位操作符类似于是对数字的二进制序列进行向左或者向右移动。其中被操作的对象数字必须为整数。
(3) 左移操作符的计算例子:
左移操作符运算规则为:将该数字二进制的补码序列左边丢弃n个数字,右边补n个0用作中和。
eg1.左移操作符
int a=10; //因为int为4字节,则a为32bit位
int b=a<<3;//参与运算的是补码,因为10是正数则原码、反码、补码相同。
printf("%d",b);
10的二进制序列为:00000000000000000000000000001010
10<<3的二进制序列为:
00000000000000000000000001010000
a<<3的意思是将a的二进制序列左边三个数字丢弃,然后再将a的二进制序列后面补3个0,最后将此值赋给b,而后打印b的值。
eg2.左移操作符
int a=-1;//因为int为4个字节,所以a的二进制序列为32位,且最高位为符号位为1。
int b=a<<1;//参与运算的是存储在内存中的补码,所以需要先将a的补码写出来。
printf("%d",b);
-1的二进制原码:
10000000000000000000000000000001
-1的二进制反码:
11111111111111111111111111111110
-1的二进制补码:(参与运算的是二进制的补吗)
11111111111111111111111111111111
-1<<1二进制补码:(参与计算的是二进制的补码)
11111111111111111111111111111110
从而得出-1<<1的二进制原码:(补码取反后+1)
10000000000000000000000000000010
化成10进制后b为-2
(4) 左移操作符运算过程中左移1位有乘2的效果
(5) 右移操作符的不同种类
右移操作符的不同形式取决于编译器的不同。右移操作符分为逻辑右移和算数右移。其中主要为算数右移。逻辑右移的运算规则为将二进制的补码序列左边用n个0填充,右边丢弃n个数字。算数右移的运算规则为将二进制的补码序列左边用该数值的n个符号位的数字填充(原来为正数则填充0,原来为负数则填充1),右边丢弃n个数字用于中和。
(6)算数右移的例子
eg.
int a=-10;//因为int为4字节,所以a的二进制序列为32位,其中最高位符号位。
int b=a>>1;//参与运算时为a的二进制补码
printf("%d",b);
a的二进制序列原码:
10000000000000000000000000001010
a的二进制序列反码:
11111111111111111111111111110101
a的二进制序列补码:
11111111111111111111111111110110
b经过算数右移后的二进制序列补码:
11111111111111111111111111111011
b的二进制原码:(补码取反+1)
10000000000000000000000000000101
输出值b=-5
(7) 右移操作符的算数右移有÷2的效果
2.位操作符(只针对整数)
(1) 位操作符包括:按位与&,按位或|,按位异或∧,按位取反~。
(2) 位操作符的运算规则:
按位与&:有0则0,全1则1。
按位或|:有1则1,全0才0。
按位异或∧:相同则0,相异则1。
按位取反~:将该数字的二进制补码序列每一位取反。
(3) 位操作符的例子:
eg1.
int a = 6;
int b = 7;
int c = a&b;
a的二进制序列补码:
00000000000000000000000000000110
b的二进制序列补码:
11111111111111111111111111111001
c的二进制序列补码:
00000000000000000000000000000000
因为c的二进制序列补码的最高符号位为0,则c为正数,原码、反码、补码均相同。所以经过计算c的值为0
eg2.
int a = 6;
int b = -7;
int c =a|b;
a的二进制补码序列:
00000000000000000000000000000110
b的二进制补码序列:
11111111111111111111111111111001
c的二进制补码序列:
11111111111111111111111111111111
c的二进制原码序列:
10000000000000000000000000000001
因为c的二进制补码序列显示c为负数,所以c的二进制原码、反码、补码各不相同,写出原码后得出c=-1。
eg3.
int a = 6;
int b = 7;
int c=a∧b;
a的二进制补码序列:
00000000000000000000000000000110
b的二进制补码序列:
11111111111111111111111111111001
c的二进制补码序列:
11111111111111111111111111111111
c的二进制原码序列:
10000000000000000000000000000001
经过计算c=-1。
eg4.
int a= 0;
int b = ~a;
printf("%d",b);
a的二进制补码序列:
00000000000000000000000000000000
b的二进制补码序列:
11111111111111111111111111111111
b的二进制原码序列:
10000000000000000000000000000001
经过计算b=-1。
(4) 位操作符的项目例子
eg1.不能创建临时变量,交换两个数的数值。
法一:
int a=3;
int b=5;
a=a+b;
b=a-b;
a=a-b;
法二:
a=a∧b;//a=3∧5
b=a∧b; //b=3∧5∧5其中5∧5为0,则b最终为3。
a=a∧b; //a=3∧5∧3其中3∧3为0,则a最终为5。
总结:a∧0等于a,a∧a等于0。且∧操作符支持交换律。
eg2.编写代码求出一个整数存储在内存中二进制1的个数
法一:
根据10进制和2进制之间的转化规则编写。10进制转化为2进制,需要将10进制数不断除以2得出余数,所得余数便是2进制序列不同位的数字。
# include
int count_bit_one ( int n )//定义一个函数用于计算一个数字二进制序列中1的个数
{
int count=0;//定义一个计数器
while(n)//定义一个while循环,当n等于0时循环停止
{
if(n%2==1)//如果n对2求余为1
count++;//则计数器加一
n=n/2;//最后n除以2,继续进入循环。
}
return count;//函数返回值为count
}
int main ( )
{
int num = 0;//定义并且初始化要求的变量num
scanf("%d",&num);//读取键盘输入的数据,存入num变量中
int ret=count_bit_one( num );//将函数返回值赋值给ret变量
printf("%d",ret);//打印ret的值,此值便是需求的答案
return 0;
}
法二:
根据已学的操作符>>和&进行编写。将需要求的数字>>i,然后&1。于是可以知道该数字num的最右位是否为1。
int count _bit _one ( int n )//定义一个函数用于计算一个数字的二进制序列中1的个数
{
for (int i=0;i<32;i++)//因为定义了一个整数为32个bit位,所以定义一个循环。使i从1增加到32。
{
if((n>>1)&1==1)//具体解释见上
count ++;//计数器加一
}
return count;//返回计数器的数值
}
法三:
根据位操作符&不断将num的最右端二进制序列的1变为0,同时计数器加一。
拓展:如何将一个数值的二进制序列的最右端数字从1变成0?————→需要n&(n-1)
int count_bit_one(int n)
{
int count =0;//定义一个计数器变量count
while(n)//定义一个循环,当n的二进制序列的每一位数字均为0时,跳出循环。
{
n&(n-1);
count++;//计数器加一
}
return count;//返回计数器的值
}
eg3.写一个代码,判断n是否为2的次方数。
拓展:2的次方数的二进制序列只有一位是1,其余位均为0,当该数的最右端二进制序列1被消去后,则该数变为0。
if(n&(n-1)==0)
printf("yes");
eg4.写一个代码,将13的二进制序列的第5位改为1之后又改为0。进而拓展为第n位。
13的二进制补码序列为:
00000000000000000000000000001101
1<<5-1
00000000000000000000000000010000
第一轮变化之后数的二进制补码序列为:
00000000000000000000000000011101
~1<<5-1
11111111111111111111111111101111
上述两者|,便可以将第五位进行替换
# include
int main ( )
{
int a=13;
int n=5;
a=a|((n-1)>>1);//将a和1向左移n-1位的数进行按位或
a=a&~((n-1)>>1);//将a和1向左n-1位的数进行按位取反后按位与。
return 0;
}
3. 单目操作符
(1) 特点:只有一个操作数
(2) 分类:!++ -- & * + - ~ sizeof (强制类型转化)
其中&为取地址操作符,*为解引用操作符。
4.逗号操作符
(1) 书写形式:表达式一,表达式二……(从左至右依次计算)
(2) eg.
int main( )
{
int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1);
printf("%d",c);
}
计算结果为c=13
结论:逗号表达式的结果为最后一个表达式的计算结果,计算顺序为从左至右。