1,不创建临时变量交换两个数
这里输入a的值,b的值,不能创建临时变量tmp实现交换
第一种:
#include<stdio.h>
int main()
{
int a, b = 0;
scanf("%d%d", &a, &b);
a = a + b;
b = a - b;//此时b=a+b-b=a
a = a - b;//此时a=a+b-a=b实现了交换a ,b的目的
printf("a=%d b=%d",a,b);
return 0;
}
(注意这种算法存在问题,因为当a,b数字很大时a+b的值可能会超过int类整形的范围,a+b的值会发生丢失)
第二种:
#include<stdio.h>
int main()
{
int a, b = 0;
scanf("%d%d", &a, &b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a=%d b=%d",a,b);
return 0;
}
这里以a=-1,b=4来举例
实现交换
2,求二进制中数字1的个数
方法1:
数字%2获得二进制位,再通过数字除2找下一位,
直到最后数字/2后为0,假停下循环
#include<stdio.h>
int main()
{
int count = 0;
int n = 0;
scanf("%d",&n);
while (n)
{
if (n % 2 == 1)
count++;
n = n / 2;
}
printf("二进制位中1的个数为%d",count);
return 0;
}
但这里有缺陷,负数的二进制位没有办法计算
负数%2余数是-1不会执行count++
方法2:
我们知道&操作符
在二进制中1&0=0,只有1&1=1
1在计算机中储存的是000000000…1
所以我们将输入的二进制数字&1
如果得到1说明二进制位最后一位是1,此后变量>>1
来检测下一位二进制数字是不是0,一共进行32次。
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d",&a);
int count = 0;
for (int i = 0; i < 32; i++)
{
int j = 1;
if ((a & j) == 1)
{
count++;
}
a = a >> 1;
}
printf("二进制中1的个数%d",count);
return 0;
}
这时负数的二进制位1的个数也可以计算
方法三:
采用相邻的两个数据进行按位与运算
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d",&a);
int count = 0;
while (a)
{
a = a & (a - 1);
count++;
}
printf("二进制位为1的个数为%d",count);
return 0;
}
当a=3时
a的二进制位为 0 1 1
a-1二进制的为 0 1 0
--------a&a-1为 0 1 0 (count=1)
此后a的二进制位为0 1 0
------a-1的二进制为0 0 1
--------------a&a-1为0 0 0 (count=2)
此时a=0为假跳出循环
在二进制位存在一个以上的1时a&(a-1)一定不可能是0,因为一定存在相同的二进制位。
当最后一位为1时a&a-1最后一位变成0,赋值给了a相当于移动了一位
当最后一位为0时a&a-1最后一位为0,赋值给了a相当于舍弃了一位
在二进制位只存在一个1时a&a-1一定是0,count加1后离开循环,最后统计的就是a中二进制位1的个数
3,求两个二进制位不同数字的个数
首先我们知到二进制位数字有两种情况0 和 1
我们首先通过异或操作将不同的数字变为1存到变量c中
在计算变量c中二进制1的个数,这里求二进制1的个数不在赘述
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d%d",&a,&b);
int c = a ^ b;
int count = 0;
for (int i = 0; i < 32; i++)
{
int j = 1;
if ((c & j) == 1)
{
count++;
}
c = c >> 1;
}
printf("%d",count);
return 0;
}
4,表达式求值
表达式求值一部分是按照操作符的优先级和结合性的顺序进行的
优先级高的先运算,当表达式优先级相同时运算方向根据结合性来看,这里不多赘述。
同时有些时候表达式的操作数可能会转化成其他类型
整形转换(隐形类型转换)
eg:
#include<stdio.h>
int main()
{
char a = 3;
char b = 137;
char c = a + b;
printf("%d",c);
return 0;
}
发现这里并不是我们想的140,
这是因为char类型大小是一个字节,而一个整形是4个字节
char—8个比特位,
int—32个比特位,
整型提升是按照符号位进行提升的符号位就是二进制位的首位
+号操作符操作的是int型,所以char类型先补到32位
a=0 0 0 0 0 0 1 1(补位,符号位为0)
a=0000…0 1 1(32位)
b= 1 1 1 1 1 1 1 1(补位)
b=0 0 0 0 0 0 1 1 1 1 1 1 1(32位)
a+b=0 0…1 0 0 0 0 0 1 0(32位)
c=a+b(c是字符类型,只能存8位,所以会发生截断)
c=1 0 0 0 0 0 1 0
printf("%d")所以c还要进行整形提升
c的符号位是1,所以补1到32位
c整型提升后
1 1 1 1 1 1…1 0 0 0 0 0 1 0(32位)(补码)
1 1 1 1 1 1…1 0 0 0 0 0 0 1(32位)(补码)
1 0 0 0 0 0…0 1 1 1 1 1 1 0(32位)(原码)
符号位为1说明是负数
翻译原码得-116
有些数字如果是无符号位数,整形提升补零
整型提升只发生在有二进制位且大小小于int的时候
发生了整型提升。
当从int转换成比int大的类型时不会出现这种情况,不会截断
计算机在计算表达式时方法不一定唯一
eg:
a*b+c*d+e*f
可以计算ab,cd,e*b,再把三者加起来,
或者把ab+cd看成一个整体先计算,然后再算e*f,再加起来,
所以表达式的运算不一定时唯一的,要注意规避这种情况。
eg:int c=(++a)+(++a)+(++a);
#include<stdio.h>
int main()
{
int a = 4;
int c = (++a) + (++a) + (++a);
printf("%d",c);
}
这里计算是先计算三次++a, a=7在求和得21
但不同编译器计算顺序不同,也可以先算两次++a(把前两个表达式看成整体),在计算后面的+(++a).
太复杂的计算式点到为止,不必深究