1.打印数字对应的二进制(并统计1出现的次数)
对于整数和浮点数来说,在计算机存储时都是通过其二进制的补码进行存储的,包括对数字的操作,本质上都是操作其二进制补码;
在32位机器下,一个整数对应着32个二进制位。对于正数来说,其原码=反码=补码;对于负数来说,反码=原码(除符号位按位取反),补码=反码+1;
打印对应的二进制为,核心思想是利用:按位与&操作符 &1
特定位数:和1&,如果原先是0,&之后还是0,如果是1,&后还是1;
获得一个整数在内存中对应二进制中1的个数 两种方法(不止一种方法) /*方法一*/ int print_binary(unsigned x) { int count = 0; unsigned int o = 1 << 31;//一定要设置为unsigned不是从首位开始比较 int i = 0; for (i = 0; i < 32; i++) { if (o & x) { printf("1"); count+=1; } else { printf("0"); } o = o >> 1; } return count; } int main() { unsigned int i; scanf("%u", &i); /*统计1出现的次数*/ unsigned int ret = print_binary(i); printf("\n1出现的次数为=%u\n", ret); return 0; } /*方法二*/ int print_binary(unsigned x) { unsigned int o = 1; int i = 0; int count = 0; for (i = 0; i < 32; i++) { if (x & o) { printf("1"); count += 1; } else { printf("0"); } x = x >> 1; } return count; } int main() { unsigned int i; scanf("%u", &i); unsigned int ret =print_binary(i); printf("\n1出现的次数为=%u\n", ret); return 0; } /*方法3*/ #include <stdio.h> int main() { int num = 15; int i = 0; int count = 0;//计数 for (i = 0; i < 32; i++) { if (num & (1 << i)) // & 一次会比较所有的二进制位 1是除了最后一位是1,其他都是0 count++; } printf("二进制中1的个数 = %d\n", count); return 0; }
补充:unsigned int 与Int的区别(详解)
- 存储数据范围不同
- Unsigned int 是无符号 整型,即首位只能为0,也即只能表示非负整数。(32位机器)范围通常为:0~4294967295
- Int 是有符号整形,即首位为0表示正数,首位为1,表示负数,(32位机器)范围通常为:-2147483648~2147483647
2.运算规则不同
在C语言中,对于有符号整数类型,进行算术运算时会考虑数值的符号,因此可能会发生溢出或者负数溢出的情况。而对于无符号整数类型,进行算术运算时不考虑数值的符号,因此不会发生负数溢出,但可能会发生无符号整数溢出。
例如,对于`int`类型,-1和1相加会得到0,但对于`unsigned int`类型,4294967295(即无符号的最大整数)和1相加会得到0。
总结:如果想存储非负整数或者处理更大的无符号数据类型,则应该使用”unsigned int”类型;如果需要存储正负正数或者处理有符号的数据,则应该使用“int ”;同时,也应该注意这两种类型都有可能发生溢出的危险;
2.循环输入的三种方式
/*循环输入的三种方法*/ /*方法一:利用scanf()的返回值为读取到的字符个数*/ int main() { int i = 0; while (scanf("%d", &i) == 1) { i = pow(i,3); printf("%d\n", i); } return 0; } /*方法二:利用EOF*/ int main() { int i = 0; //scanf函数读取失败返回的EOF while (scanf("%d", &i)!= EOF) //EOF=end of file(=-1),按ctrl+z结束循环(vs中要按三次) { i = pow(i, 3); printf("%d\n", i); } return 0; } /*方法3:利用~操作符*/ int main() { int i = 0; //-1 :10000000000000000000000000000001 while (~scanf("%d",&i)) //反码:11111111111111111111111111111110 { //补码:11111111111111111111111111111111 i = pow(i,3); //~(-1)=0 printf("%d\n", i); //如果读取失败,返回EOF(-1),取反变为0,刚好循环结束 } return 0; }
3.交换两个两个变量值 的三种方法
/*交换两个整数的三种方法以及他们的不足*/ /*方法一 :创建临时变量*/ int main() 方法比较繁琐 { int a = 10; int b = 20; int temp = 0;//临时变量 //赋值过程 temp = a; a = b; b = temp; printf("a=%d b=%d", a, b); return 0; } /*方法二:使用^操作符*/ //不太好想 只针对二进制为改变,不会有溢出的风险 int main() { int a = 10; int b = 20; int temp = 0;//临时变量 //赋值过程 a = a ^ b; //理解两个最基本的^操作运算即可 b = a ^ b; //1:a ^ a = 0; 自己异或自己=0(因为每一位都相同) a = a ^ b; //2:0 ^ a = a; 0异或一个数=异或的数(0^1=1 0^0=0) printf("a=%d b=%d", a, b); return 0; } /*方法三*/ /*创建c变量,存储a+b的和,再通过相减,完成赋值*/ 容易想,但是c有可能发生溢出(超过int 类型的最大值),造成数据丢失 int main() { int a = 10; int b = 20; int temp = 0;//临时变量 //赋值过程 int c = a + b; a = c - a; b = c - b; printf("a=%d b=%d", a, b); return 0; }
4.改变特定位数0/1
核心思想:利用&操作符和~操作符(& :一假俱假 ~ :一真俱真)
/*改特定位数的0/1*/ int main() { int a = 13; //00000000000000000000000000001101 把第五个0变为1,0^1=1,其他位不变 //00000000000000000000000000010000 //00000000000000000000000000011101 a = a ^ (1 << 4); printf("%d\n", a); //=29 //把a变回去 //00000000000000000000000000011101 把第五个1变为0,1&0=0,其他位不变 //11111111111111111111111111101111 =~(1<<4) a = a & (~(1 << 4)); printf("%d\n", a); return 0; //理解就好,&一假具假,所以容易出现0,^一真俱真,所以容易出现1 }
5.&&和||的连续操作(与前置,后置结合)
核心思想:&&只要遇到0(假),后面就不用计算了,就是断路了;同理,||只要遇到1(真),后面也发生断路,不需再计算;
代码如下:
//& ^关注的二进制位的变化 单目操作符 //&& || 只关注真假 逻辑操作符 计算结果是真,返回1 //&& 一假具假 || 一真俱真 int main() { int a = 1; int b = 2; int c = 3; /*a--是先执行&&的操作,再进行a=a-1*/ int i = a-- && ++b && c++; printf("%d %d %d", a, b, c);//0 3 4 return 0; } int main() { int a = 1; int b = 2; int c = 3; /*a--是先执行&的操作,再进行a=a-1*/ int i = a++ || ++b || c++; printf("%d %d %d", a, b, c);//2 2 3 return 0; }