(C语言)操作符练习题(多种方法求解)

1.写一个函数返回参数二进制中1的个数

1.1解法1

如果我们想得到一个十进制位数它的每一位,我们可以不停的%10/10//1234
1234%10=4
1234/10=123
123%10=3
123/10=12
12%10=2
12/10=1
1%10=1
1/10=0
//一直到/10=0停止

同样的,如果我们想得到一个二进制位数它的每一位;
//11(十进制)->1011(二进制)
11%2=1
11/2=5->101(二进制)
5%2=1
5/2=2
2%2=0
2/2=1
1%2=1
1/2=0

代码如下

int count_num_of_1(int n)
{
	int count = 0;
	while (n)
	{
		if (n % 2 == 1)
		{
			count++;
		}
		n /= 2;
	}
	return count;
}
int main()
{
	int num = 0;
	scanf("%d", &num);
	int n=count_num_of_1(num);
	printf("%d\n", n);
}

但是这样写对负数不适用,比如当输入-1时,进入函数内部,-1%2=-1!=1,count不变还是等于0,-1/2=0,while(0)退出循环,返回count等于0.

其实只要把其中一步改一下就行了

int count_num_of_1(unsigned int n)

函数输入一个无符号数

//-1
10000000000000000000000000000001(原码)
11111111111111111111111111111110
11111111111111111111111111111111(补码)

把-1转换为无符号数,那么第一位的1就不是符号位,-1转化为无符号数等于2^32-1,一个非常大的正数,然后可以正常进行%2,/2运算,计算1的个数

在这里插入图片描述

1.2解法2

一个数&1,结果为1,那么它二进制位的最低位为1;结果为0,那么它二进制位中最低位为0。然后>>将这个数的每一位都&1,这样就可以得到这个数二进制位的每一位。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int count_num_of_1(int n)
{
	int count = 0;
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (((n >> i) & 1) == 1)
		{
			count++;
		}
	}
	return count;
}
int main()
{
	int num = 0;
	scanf("%d", &num);
	int n = count_num_of_1(num);
	printf("%d\n", n);
}

这个解法对负数也适用。

1.3解法3

这种方法不容易想到

n=n&(n-1)
n=15
1111 n
1110 n-1
1110 n
1101 n-1
1100 n
1011 n-1
1000 n
0111 n-1
0000 n

我们可以发现n=n&(n-1)这个表达式每运行一次,二进制位中最右边的1就被去掉了,所以这个表达式运行了几次就代表二进制位中有几个1。

int count_num_of_1(int n)
{
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}
int main()
{
	int num = 0;
	scanf("%d", &num);
	int n = count_num_of_1(num);
	printf("%d\n", n);
}

这个解法对负数也适用。

n&(n-1)这个表达式还有一个用途
判断一个数是不是2^n.

if(n&(n-1)==0)

因为n&(n-1)这个表达式执行一次去掉一个1,而2^n的二进制位中只有一个1,去掉就为0.

2.两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?

2.1解法1

我们可以把两个数二进制位中每一位都取出来,挨个进行比较。

int count_diff_bit(int m, int n)
{
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (((m >> i) & 1) != ((n >> i) & 1))
		{
			count++;
		}
	}
	return count;
}
int main()
{
	int m = 0;
	int n = 0;
	scanf("%d %d", &m, &n);
	int ret=count_diff_bit(m, n);
	printf("%d\n", ret);
	return 0;
}

2.2解法2

^ 异或操作符
相同为0;不同为1
通过计算1的个数,可以得到有多少个位不同。

int count_diff_bit(int m, int n)
{
	int count = 0;
	int ret = m ^ n;
	while (ret)
	{
		ret = ret & (ret - 1);
		count++;
	}
	return count;
}
int main()
{
	int m = 0;
	int n = 0;
	scanf("%d %d", &m, &n);
	int ret = count_diff_bit(m, n);
	printf("%d\n", ret);
	return 0;
}

3.获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列。

可以用到前面获取二进制每一位的算法。

int main()
{
	int num = 0;
	scanf("%d", &num);
	//10
	//00000000000000000000000000001010
	int i = 0;
	for (i = 30; i >= 0; i -= 2)
	{
		printf("%d ", (num >> i) & 1);
	}
	printf("\n");
	for (i = 31; i >= 1; i -= 2)
	{
		printf("%d ", (num >> i) & 1);
	}
	printf("\n");
	return 0;
}

4.下面代码的结果是:

#include <stdio.h>
int i;  //0
int main()
{
    i--;  /-1
    if (i > sizeof(i))  //-1>4
    {
        printf(">\n");
    }
    else
    {
        printf("<\n");
    }
    return 0; 
}
题目内容:
A .>
B .<
C .不输出
D .程序有问题

全局变量,静态变量都是放在静态区的。
全局变量和静态变量不初始化的时候,默认都会被初始化为0。
局部变量,是放在栈区的,不初始化,默认值是随机值。

sizeof这个操作符计算返回的结果是size_t类型的,是无符号整型。

在这里插入图片描述

if (i > sizeof(i))  // -1>4

-1是一个有符号数,它和4这个无符号整数进行比较时,会进行算数转换

类型小于整型的,要进行整型提升。

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类
型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

在这里插入图片描述

从下到上进行转换。

-1就转换成无符号数,是一个非常大的数
4,294,967,295

(unsigned int)-1>(unsigned int)4

所以输出结果为:

>

5.输入月份和天数,计算这一年这个月有多少天。

月份天数
131
228(平年)/29(闰年)
331
430
531
630
731
831
930
1031
1130
1231
int is_leap_year(int y)
{
	return ((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0));//&&,||,算出结果为真->1;结果为假->0.
}//判断是否为闰年,是返回1,不是返回0
int main()
{
	int y = 0;
	int m = 0;
	int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	while (scanf("%d %d", &y, &m) == 2)
	{
		int d = days[m];//输入的月份对应数组的下标
		if (is_leap_year(y) == 1 && m == 2)//是闰年的二月天数+1
		{
			d++;
		}
		printf("%d\n", d);
	}
	return 0;
}
  • 19
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值