统计整数在二进制中1的个数:
这是上一篇文章留下的问题,这里为大家作答:
//统计二进制中1的个数
int statistics(int a)
{
int count = 0;
for (int i = 0; i < 32; i++)
{
if (a & 1)
{
count++;
}
a = a >> 1;
}
//while (a)
//{
// a = a & (a - 1);//每次都会消去一个1
// count++;
//}
return count;
}
int main()
{
int a = 0;
scanf("%d", &a);
int num = statistics(a);
printf("%d\n", num);
}
未被注释的部分就是运用位操作符实现的代码,注释的部分也是一种方法,但是这种方法很少被想到。
赋值操作符
赋值操作符就是 = 可以为变量赋上一个自己满意的值:
int num;
num = 10;//这就是赋值
并且赋值可以连续使用:
int a;
int b;
int c;
a = b = c+1;
但是同样的意思下分开写不是更让人知道且易于调试:
a = b;
b = c+1;
复合赋值符
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
这些都是复合赋值操作符
单目操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节单位)
~ 对一个数的二进制按位取反(~0 就是 -1)
-- 前置或后置--
++ 前置或后置++
* 解引用操作符
(类型) 强制类型转换
特别重点:sizeof和数组
来看一段代码:这里的1 2 3 4 会输出什么?
void teer1(int arr[])
{
printf("3:%d\n", sizeof(arr));
}
void teer2(char arr[])
{
printf("4:%d\n", sizeof(arr));
}
int main()
{
int arr1[10] = { 0 };
char ch[10] = { 0 };
printf("1:%d\n", sizeof(arr1));
printf("2:%d\n", sizeof(ch));
teer1(arr1);
teer2(ch);
}
我们说过数组名其实是首元素的地址,但是sizeof是一个特例,sizeof计算的是整个数组,但是函数传参传的是数组名也就是地址,地址的大小都是一样的。
关系操作符
>
>=
<
<=
!=
==
注意:==才是比较 ,= 是赋值
逻辑操作符
&&
||
逻辑与,逻辑或的特点:
#include<stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;//逻辑与&& 如果前面已经知道为假了,后面就都不会计算了。
printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);
}
#include<stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ || ++b || d++;//逻辑或|| 如果知道前面有一个为真了,后面也不会计算了。
printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);
}
条件操作符
exp1 ? exp2 : exp3;
条件操作符,最常用的方式就是找两个数的最大数:
int a = 5;
int b = 6;
int i = 0;
i = a > b ? a : b;
逗号表达式
exp1,exp2,exp3,.......
逗号表达式就是用逗号把多个表达式隔开,是从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
int a = 1;
int b = 2;
int c = (a>b,a=b+10,b=a+1);
上述代码中,c 是多少? 答案是13。
表达式求值
隐式类型转换:
C语言中整数运算是以整形类型精度进行的,为了这个精度,表达式中的字符和短整型在使用前会被转换为普通整形,这种转换被叫做整形提升
char a,b,c;
.......
a = b + c;
b 和 c 就会被提升为普通整形,然后在执行加法,加法之后结果会被截断,然后再存储在a 中。
如何整形提升的
整形提升是按照变量的数据类型的符号位来提升。
char c1 = -1;
变量从c1的二进制补码是8个比特位
11111111
因为char是有符号的char
所以高位补充符号位,即1:
11111111111111111111111111111111
char c2 = 1;
变量c2的二进制补码也是8个比特位
00000001
因为是有符号的char
所以高位补充符号位,即0:
00000000000000000000000000000001
算术转换:
如果某个操作符的各个操作数属于不同的类型,那么必须进行操作数的类型转换,否则无法进行操作,下面是寻常算术转换:
long double
double
float
unsigned long int
long int
unsigned int
int
如果在这个排行中排名低,那么要转换成高的才可以进行运算。
算术转换要合理,要不然有潜在问题
操作符的属性
复杂表达式的求值有三个影响的因素:
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序
注意:函数的调用先后顺序无法通过操作符的优先级确定,类如下面代码就是有问题的:
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf("%d\n", answer);
}
总结:两个相邻的操作符先执行哪个,取决于优先级,如果相同,取决于他们的结合性(可以在网上查)。如果我们的表达式无法通过操作符的属性确定唯一的计算路径,那么就是有问题的。