在前面的文章里,已经对基本上大概所有的操作符都进行了讲解,本章主要针对之前未曾讲解过的,以及一些博主认为很重要的进行讲解。
移位操作符
移位操作符一共有两个,一个是左移操作符:<<,一个是右移操作符:>> 他们两个很好区分,看箭头指向的方向,指向左就是左移操作符,指向右,就是右移操作符。
我们还要知道,移位移动的是什么,其实移动的就是一个整数的二进制位
首先我们要知道一个整数的二进制位怎么表示。我们日常见到的数,都是以十进制的形式表现出来的,即用0-9来表示,而在二进制里,只能用0和1来表示一个整数,大家看如下图形就很好理解了:
再举两个例子:
了解这个二进制的转化后,我们接下来了解什么是原码、反码、补码
刚刚我们转化过来的就是这个数的原码,而正数的原码、反码、补码都是相同的
正数 原、反、补相同 负数 反码:原码的符号位不变,其余取反 补码:反码+1
移位操作符就是移动的补码
左移操作符<<:左边丢弃,右边补0。看实例:
#include<stdio.h>
int main()
{
int a=4;
printf("%d", a<<1);
return 0;
}
讲解:
如果是负数,就要先求出它的补码,再<<,且听详细分析:
#include<stdio.h>
int main()
{
int a=-4;
printf("%d", a<<1);
return 0;
}
讲解:
接下来我们看右移操作符 >> 右移操作符又分为逻辑右移和算数右移 逻辑右移:右边丢弃,左边补0 算数右移:右边丢弃,左边补原符号位(编译器一般都是算术右移)
#include<stdio.h>
int main()
{
int a=4;
printf("%d", a>>1);
return 0;
}
负数也同理。
位操作符
&:按位与|:按位或^:按位异或
&:按位与——对应的二进制,有0则为0,两者为1则为1。具体什么意思呢?看如下案例:
#include<stdio.h>
int main()
{
printf("%d", 4 & 5);
return 0;
}
最终结果还是4.
|:按位或——只要有1,对应二进制则为1,两者为0则为0
这次举个负数的案例:
#include<stdio.h>
int main()
{
printf("%d", -4 | 5);
return 0;
}
^:按位异或——相同为0,相异为1
#include<stdio.h>
int main()
{
printf("%d", -4 ^ 5);
return 0;
}
练习题
题目:写一个函数返回参数二进制中 1 的个数。
思路:我们知道1的二进制位只有最右一位为1,其余都是0,假如这个数是a,我们上面学过了,&只有两者同时为1得到的二进制才为1,那假如我们用a的最右位按位与1,由于1的其余位都是0,所以只有最右位为1时得到的才是1,然后我们再把a右移,循环32次,把得到结果为1的统计起来就可以了
代码如下:
#include<stdio.h>
int cont_bit(int a)
{
int cont = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if (1 == (a & 1))
{
cont++;
}
a >>= 1;
}
return cont;
}
int main()
{
int a = 0;
scanf("%d", &a);
int cont = cont_bit(a);
printf("%d", cont);
return 0;
}
我们上面知道100的二进制位右有3个1,这个代码能不能实现呢?
可以看出确实如此。这种方法是最容易想到的,也很好理解,当然还有其它方法,在这里就不一一讲解了,有兴趣的可以自己研究一下。
sizeof与数组
我们在上一章一维数组与二维数组的讲解里,就讲到了数组名是首元素地址,只有sizeof(数组名),这里的数组名才表示整个数组。那么大家看如下代码:
#include <stdio.h>
void test1(int arr[])
{
printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr));//(1)
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0; }
这里的(1)、(2)、(3)、(4)的值分别是多少呢?
我相信肯定很多人都回答不对,正确答案应该是40 4 10 4首先,1和3大家肯定都知道,因为sizeof数组名求的是整个数组大小,arr是整型数组,一个元素4个字节,10个元素就是40,ch为字符类型数组,一个元素占1个字节,一共10个,也就是10
那么问题就出在2和4了,我们要知道,这里的2和4里面的arr和ch其实是test()函数传过去的,test()函数传过去的是首元素地址,而一个地址在32位机器下储存起来需要32个比特位空间,也就是4个字节,它跟类型是没关系的,只要是地址,32机器下存储就需要4个字节,所以2和4的大小都是四个字节,这里最容易出错。!!!
逻辑操作符
在前面章节也讲过了&&与||
这里有一点需要注意:a && b && c假如a为假,那么整体就为假,后面的b 和 c 都不会进行运算,因为&&相当于并且假如a真,b假,整体就为假,那么c就不会参与运算而a || b || c, ||相当于或者,只要有一个为假,就整体为假假如a为真,b为假,整体就为假,c就不会参与运算
360笔试题
1、
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0; }
2、
#include <stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
1首先,第一个,a++ && ++b && d++这里a为0,在C语言里,0代表假,所以b和d都不会参与运算,而a++表示先使用a,a再增加,所以这里的a用完后还要加1,所以abcd为: 1 2 3 4
2这里i = a++||++b||d++;a=0为假,进行b的运算,++b,此时b=3,为真,整体就为假,d就不运算,a用完后还要++所以a=1,b=3,c=3,d=4,
整型提升
有些表达式的操作数在求值的过程中可能需要转换为其他类型。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令 中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转 换为int或unsigned int,然后才能送入CPU去执行运算
具体什么意思呢?看如下代码:
#include <stdio.h>
int main()
{
char a = 1;
char b = 2;
char c = a + b;
printf("%d", c);
}
算数转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。():类型强制转换
long double doublefloatunsigned long intlong int unsigned int int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
标签:return,int,++,详解,操作符,printf,main From: https://blog.51cto.com/u_15954929/6057448