首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C语言编程实战:大家一起云刷题 - day3

C语言编程实战:大家一起云刷题 - day3

作者头像
say-fall
发布2026-01-15 10:19:57
发布2026-01-15 10:19:57
440
举报
在这里插入图片描述
在这里插入图片描述

🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言 🔥专栏:《C语言从零开始到精通》 《C语言编程实战》 《数据结构与算法》 《小游戏与项目》 💪格言:做好你自己,你才能吸引更多人,并与他们共赢,这才是你最好的成长方式。


前言:

本系列博客将会更新一些每日的刷题代码以及对题目的解读,帮助大家更好地理解编程思路和实现方法


题目:

1. n的阶乘

  • 递归和非递归分别实现求n的阶乘(不考虑溢出的问题)

阶乘的定义是n! = n × (n-1) × … × 1,其中0!和1!都为1。下面分别用递归和循环(非递归)的方式实现:

代码语言:javascript
复制
//递归和非递归分别实现求n的阶乘(不考虑溢出的问题)
#include<stdio.h>
//递归实现:将大问题分解为规模更小的子问题,直到达到终止条件
int fact(int n)
{
	//终止条件:1的阶乘是1,2的阶乘是2(也可简化为n<=1时返回1)
	if (n == 1 || n == 2)
	{
		return n;
	}
	else
	{
		//递归公式:n! = n × (n-1)!
		return n * fact(n - 1);
	}
}

int main()
{
	//测试递归实现,计算6的阶乘
	printf("%d\n", fact(6));
	
	//循环(非递归)实现:通过迭代累乘得到结果
	int n = 6;
	int facter = 1; //初始化乘积为1(乘法的单位元)
	while (n > 0)
	{
		facter *= n; //累乘当前值
		n--; //逐步减小数值,直到n变为0
	}
	printf("%d\n", facter);
	return 0;
}

2. 打印一个整数的每一位

  • 递归方式实现打印一个整数的每一位

要打印一个整数的每一位(如951打印为9 5 1),可以通过递归不断提取高位数字,直到剩下最后一位时开始打印,从而实现从高位到低位的输出。

代码语言:javascript
复制
//递归方式实现打印一个整数的每一位
#include<stdio.h>
//递归实现:先处理高位,再打印当前位
void print(int n)
{
	//终止条件:如果n是个位数,直接打印
	if (n < 10)
	{
		printf("%d ", n);
	}
	else
	{
		//先递归处理去掉最后一位的数(获取高位)
		print(n / 10);
		//再打印最后一位(通过取余10得到)
		printf("%d ", n % 10);
	}
}

int main()
{
	//测试:打印951的每一位
	print(951); //输出结果:9 5 1 
	return 0;
}

3. 交换两个变量(不创建临时变量)

  • 不允许创建临时变量,交换两个整数的内容

通常交换两个变量需要借助临时变量,这里利用异或()的特性实现无临时变量交换。异或的特点是:aa=0,a^0=a,且满足交换律和结合律。

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	int a = 6;
	int b = 12;
	printf("交换前:a=%d b=%d\n", a, b);
	
	//第一步:a存储a和b的异或结果(a^b)
	a = a ^ b;
	//第二步:b = (a^b) ^ b = a ^ (b^b) = a ^ 0 = a(此时b的值变为原来的a)
	b = a ^ b;
	//第三步:a = (a^b) ^ a(新b是原a)= (原a^原b) ^ 原a = 原b ^ (原a^原a) = 原b ^ 0 = 原b
	a = a ^ b;
	
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

4. 统计二进制中1的个数

  • 二进制中1的个数

统计二进制中1的个数可以利用位运算的技巧:n & (n-1) 会消除n二进制中最后一个1。通过循环执行该操作,直到n变为0,执行的次数就是1的个数。

代码语言:javascript
复制
//写一个函数返回参数二进制中 1 的个数。
//比如: 15    0000 1111    4 个 1
#include<stdio.h>
void Count(int n)
{
	int count = 0; //计数器,记录1的个数
	while (n != 0)
	{
		//n & (n-1) 会消除n的二进制中最后一个1
		n = n & (n - 1);
		count++; //每消除一个1,计数器加1
	}
	printf("%d\n", count);
}

int main()
{
	int n = 0;
	scanf("%d", &n); //输入一个整数
	Count(n); //统计并打印该整数二进制中1的个数
	return 0;
}

5. 求两个数二进制中不同位的个数

  • 编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?

输入例子:

  • 1999 2299
  • 输出例子:7

关键思路是利用异或(^)操作:两个数异或后,结果的二进制中,1的位置就是两个数二进制不同的位置。因此,只需统计异或结果中1的个数即可。

代码语言:javascript
复制
#include <stdio.h>

//统计一个数二进制中1的个数(复用第4题的逻辑)
int Count(int n)
{
	int count = 0;
	while (n != 0)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}

int main() {
    int a, b;
    //循环读取输入,直到文件结束(EOF)
    while (scanf("%d %d", &a, &b) != EOF) 
    { 
        //a^b的结果中,1的位置即为a和b二进制不同的位置
        int c = a ^ b;
        //统计c中1的个数,即为不同位的数量
        int count = Count(c);
        printf("%d\n", count);
    }
    return 0;
}

6. 单身狗1

  • 在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。
  • 例如:

数组中有:1 2 3 4 5 1 2 3 4,只有5出现一次,其他数字都出现2次,找出5

这里使用双重循环的暴力解法:遍历每个元素,统计其在数组中出现的次数,次数为1的即为目标数字。(更优的解法可以利用异或特性:aa=0,0a=a,将所有元素异或后结果即为只出现一次的数字)

代码语言:javascript
复制
//在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。
//数组中有:1 2 3 4 5 1 2 3 4,只有5出现一次,其他数字都出现2次,找出5
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,5,4,6,3,2,1 }; //示例数组,6是只出现一次的数字
	int sz = sizeof(arr) / sizeof(arr[0]); //计算数组元素个数
	
	//遍历数组中的每个元素
	for (int i = 0;i < sz;i++)
	{
		int count = 0; //统计当前元素出现的次数
		//再次遍历数组,计数与当前元素相等的元素个数
		for (int j = 0;j < sz;j++)
		{
			if (arr[i] == arr[j])
			{
				count++;
			}
		}
		//如果次数为1,说明找到目标数字
		if (count == 1)
			printf("%d",arr[i]);
	}
	return 0;
}

7. 打印整数二进制的奇数位和偶数位

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

整数的二进制位从右向左(即从低位到高位)编号,最右边为第1位(奇数位),第2位为偶数位,以此类推。通过循环取余和除法提取每一位,分别存入奇数位和偶数位的数组,最后打印即可。

代码语言:javascript
复制
//获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
#include <stdio.h>
void print(int n)
{
	int count = 0; //记录当前是第几位(从1开始)
	int arr1[16] = {0}; //存储奇数位(第1,3,5,...位),int型共32位,故最多16个奇数位
	int arr2[16] = {0}; //存储偶数位(第2,4,6,...位),最多16个偶数位
	
	while (n != 0)
	{
		int m = n % 2; //提取当前最低位(0或1)
		count++; //位数加1
		
		//判断当前位是奇数位还是偶数位,存入对应数组
		if (count % 2 != 0) //奇数位(第1,3,5...位)
		{
			arr1[(count - 1)/2] = m; //计算存储位置(0,1,2...)
		}
		else //偶数位(第2,4,6...位)
		{
			arr2[count/2 -1] = m; //计算存储位置(0,1,2...)
		}
		n = n / 2; //移除已经处理的最低位
	}
	
	//打印奇数位(从右向左,即从第1位开始)
	printf("奇数位,从右向左依次:");
	for (int i = 0;i < 16; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	
	//打印偶数位(从右向左,即从第2位开始)
	printf("偶数位,从右向左依次:");
	for (int i = 0;i < 16; i++)
	{
		printf("%d ", arr2[i]);
	}
}


int main()
{
	print(0b1111); //测试二进制1111(十进制15),其奇数位为1,1,偶数位为1,1
	return 0;
}

知识点

1. 右移操作符

在计算机中,右移运算(>>)是对二进制位的操作,根据处理符号位的方式不同,分为逻辑右移算术右移,二者的核心区别在于移位后左侧空出的位如何填充。下面详细讲解:

1.1. 逻辑右移(Logical Right Shift)
  • 规则:不管原数是正数还是负数,右移时左侧空出的位一律用 0 填充,右侧超出边界的位直接丢弃。
  • 适用场景:通常用于无符号整数(unsigned),因为无符号数没有符号位,仅表示数值大小。
  • 示例: 以 8 位二进制为例,对无符号数 0b10110100(十进制 180)进行逻辑右移 2 位: 原二进制:10110100 右移 2 位后:00101101(左侧补 0,右侧丢弃最后 2 位) 结果为十进制 45
1.2 算术右移(Arithmetic Right Shift)
  • 规则:右移时,左侧空出的位用原数的符号位(最高位)填充,右侧超出边界的位直接丢弃。
    • 若原数是正数(符号位为 0),则左侧补 0;
    • 若原数是负数(符号位为 1),则左侧补 1。
  • 适用场景:主要用于有符号整数(signed),目的是保持移位后数值的符号不变(即移位后与原数同号),且近似于“除以 2 的 n 次方”(向下取整)。
  • 示例: ① 正数右移:8 位有符号数 0b00110100(十进制 52)算术右移 2 位: 原二进制:0 0110100(符号位为 0) 右移 2 位后:0 0001101(左侧补符号位 0) 结果为十进制 13(52 ÷ 4 = 13,符合预期)。 ② 负数右移:8 位有符号数 0b11001100(十进制 -52,补码表示)算术右移 2 位: 原二进制:1 1001100(符号位为 1) 右移 2 位后:1 1110011(左侧补符号位 1) 结果为十进制 -13(-52 ÷ 4 = -13,符合预期)。
1.3 关键区别总结

类型

左侧填充值

适用数据类型

核心目的

逻辑右移

固定填充 0

无符号整数(unsigned)

仅移动位,不考虑符号

算术右移

填充原符号位

有符号整数(signed)

保持符号不变,近似除以 2ⁿ

1.4 C 语言中的右移规则

C 语言标准没有明确规定有符号数的右移是逻辑右移还是算术右移,具体由编译器实现(大多数编译器对有符号数采用算术右移,对无符号数采用逻辑右移)。例如:

代码语言:javascript
复制
int a = -52;       // 二进制补码:11111111 11111111 11111111 11001100(32位)
a = a >> 2;        // 算术右移后:11111111 11111111 11111111 11110011(结果为 -13)

unsigned int b = 180; // 二进制:00000000 00000000 00000000 10110100
b = b >> 2;           // 逻辑右移后:00000000 00000000 00000000 00101101(结果为 45)

因此,在处理有符号数的右移时,需注意编译器的行为,避免依赖未定义的操作。


  • 本节完…
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 题目:
    • 1. n的阶乘
    • 2. 打印一个整数的每一位
    • 3. 交换两个变量(不创建临时变量)
    • 4. 统计二进制中1的个数
    • 5. 求两个数二进制中不同位的个数
    • 6. 单身狗1
    • 7. 打印整数二进制的奇数位和偶数位
  • 知识点
    • 1. 右移操作符
      • 1.1. 逻辑右移(Logical Right Shift)
      • 1.2 算术右移(Arithmetic Right Shift)
      • 1.3 关键区别总结
      • 1.4 C 语言中的右移规则
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档