学习总结(位操作符;循环输入的三种方式;交换两个变量值的三种方法;打印数字对应的二进制;unsigned int 与int 的区别;改变特定位数0/1;&&和||的连续操作(与前置,后置结合))

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的区别(详解)

  1. 存储数据范围不同 
    1. ​​​​Unsigned int 是无符号 整型,即首位只能为0,也即只能表示非负整数。(32位机器)范围通常为:0~4294967295
    2. 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;
}

注意:&,^和&&,||根本不是一个东西;前者是单目操作符,进行的是二进制的转换;后者是逻辑操作符,是进行逻辑判断的,只会返回0或1;

猜你喜欢

转载自blog.csdn.net/Mylvzi/article/details/130634692