操作符学习
1.移位操作符
左移操作符:<<;右移操作符:>>
注意:他们的操作数必须是整数,并且不要移动负数位,e.g.10>>(-1)
左移操作符,左面抛弃,右面补0
右移操作符,逻辑右移或者算术右移,逻辑右移右面抛弃,左面补0;算术右移,右面抛弃,左面补符号位
左移一位相当于乘2,右移一位相当于除以2。
可以用右移来求平均值。
e.g.(left + right) >> 1
2.位操作符
按位与、按位或、按位异或、按位取反,操作数都必须为整数
e.g.1
不创建中间变量的情况下,实现两个数的交换
int main()
{
int a = 10, b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a = %d b = %d\n", a, b);
return 0;
}
按位异或的神奇之处
int main()
{
int a = 10;
int b = 20;
int c = a ^ a;//c=0,因为相同取0,不同取1
int d = c ^ b;//d=b
int e = a ^ a ^ b;//e = b
int f = a ^ b ^ a;//f = b,可以交换律
}
这个用法是按位异或比较巧妙的一个使用方法,值得大家学习一下。
e.g.2
一个数在计算机中的二进制存储形式里有多少个1
int main()
{
int a = 0, i = 0;
printf("请输入:>");
scanf("%d", &a);
while (a)
{
if (a % 2 == 1)
{
i++;
}
a = a / 2;
}
printf("%d\n", i);
return 0;
}
int main()
{
int a = 0, i = 0, count = 0;
printf("请输入:>");
scanf("%d", &a);
for (i = 0; i < 32; i++)
{
if ((a & (1 << i)) != 0 )
{
count++;
}
}
printf("%d\n", count);
return 0;
}
int main()
{
int a = 0, i = 0;
printf("请输入:>");
scanf("%d", &a);
while (a)
{
i++;
a = a & (a - 1);
}
printf("%d\n", i);
return 0;
}
三种方法,都要掌握。
e.g.3
求两个数二进制中不同位的个数
int main()
{
int a = 0, b = 0, i = 0;
scanf("%d%d", &a, &b);
int c = a ^ b;
while(c)
{
i++;
c = c & (c - 1);
}
printf("%d\n", i);
return 0;
}
先试用按位异或的性质,相同为0,不同为1,接着在变成找一个数二进制位的1的个数。
3.逗号表达式
从左向右依次执行,最后的结果是最后一个表达式的结果
int main()
{
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);
printf("%d\n", c);//c=13
return 0;
}
4.下标引用[]和函数调用()
int arr[10];//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。
//[ ]的两个操作数是arr和9。
函数调用操作符:接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。
5.优先级和结合性
优先级
常用: 自加自减 > ! > 运算操作符 > 关系操作符(大于和小于高于!=和==)> && || > 赋值操作符
参考:
6.整型提升和算术转换
1.整型提升
C语言的整型算术运算总是至少以缺省整型类型(计算机整型默认的类型-int)的精度来进行的,为了获得这个精度,表达式中的字符和短整形操作数**在使用前(参与算术运算之前)**都会被转换为默认的普通整型,这种转换称为整型提升。
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度⼀般就是int的字节长度,同时也是CPU的通⽤寄存器的长度。
有符号整数提升是按照变量的数据类型的符号位来提升的,负数补1,正数补0
无符号整数提升, 高位补0
因为-1整型提升后是在内存中的二进制存储形式是32个1,无符号数自然会很大。
至于++a和–a为什么还是1,因为a=a+1和a=a-1最后的本质还是求sizeof(a)
2.算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另⼀个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
//long double
//double
//float
//unsigned long int
//long int
//unsigned int
//int
从下到上转换
e.g.
#include <stdio.h>
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
最后输出>
C语言中,0为假,非0即为真。
全局变量,没有给初始值时,编译其会默认将其初始化为0。
i的初始值为0,i–结果-1,i为整形,sizeof(i)求i类型大小是4,按照此分析来看,结果应该是<,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,故实际应该是>