C:关于位操作符:、|、^、~的一些应用

news2024/9/22 21:36:42

一些用来熟悉位操作符的应用

一、按位异或:^

异或运算:相同为0,相异为1

应用:在不引入临时变量(第三变量)的情况下,实现两个整数的交换。

关于两个整数交换,我们有一些方法,比如说,创建一个第三变量,就可以很轻易的实现两个整数的交换,如下代码:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d b=%d\n", a, b);
	int c = a;
	a = b;
	b = c;
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

但是,该程序引用了第三个变量,如果不引入第三个变量,我们又有什么办法来实现两个整数的交换呢?

这里我们就可以使用按位异或操作符^来达到想要的目的。

代码展示:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d b=%d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

相信你看到这个程序可能会有一点懵并充满疑惑,这是怎么实现的?

在解析这串代码之前,我们需要了解一些知识来为读懂代码做准备。

异或运算:相同为0,相异为1

int a =3;

int b = 5;

a的二进制表示:011

b的二进制表示:101

1. a^a = 0

a = 011

a = 011

a^a = 000

我们可以知道,整数和它自己本身异或得到的结果是0

2. a^0 = a

a = 011

0 = 000

a^0 = 011

我们可以得到,整数和0异或得到的结果是整数本身

当我们知道这些信息后,我们就可以解析这串代码了

a = a ^ b;
b = a ^ b;
a = a ^ b;

 开始时,将a ^ b的值赋给a,因此,b = a ^ b表达式中的a的值就变为a ^ b,通过异或运算,我们可以得到b=a,这时候,b的值就变为a了,但是a的值没有变化,还是 a ^ b,因此,在a = a ^ b表达式中, a ^ b中a的值还是a ^ b,b的值变为了a,通过异或运算,我们可以得到 a=b。

下面是图解:

图片或许表达的不是很清楚,如果有不明白的,可以私我,欢迎!

二、按位与:&

与运算:有0为0,全1为1

应用:求一个整数存储在内存中的二进制中1的个数

法一:通过判断整数的最后一位

int n = 15;  
int count = 0;//二进制中1的个数

将15与1进行 与运算 15&1

00000000000000000000000000001111   //15的二进制表示
00000000000000000000000000000001  // 1的二进制表示
00000000000000000000000000000001  //与运算结果
通过与运算结果是1,我们可以判断出15的最低位是1

因此,如果想得到n的二进制最低位,我们就可以给n按位与上一个1,通过判断结果是0还是1来确定n的二进制最低位是什么。

当我们得到最后一位后,如果结果是1的话,我们就count++,该最低位统计过后,我们需要统计倒数第二位,该怎么办呢?

我们可以通过右移操作符 >> 向右移动一位,这样就可以丢掉已经统计过的最低位,这样倒数第二位就来到了最低位,然后再按位与1,判断结果,如果结果是1,就count++,如果结果是0,则count的值不变,重复操作32次后,我们就可以判断完每一位是否为1,从而得到整数存储在内存中的二进制中1的个数。

for (int i = 0; i < 32; i++)//一个整型是4个字节,一个字节8个bit,这里的32就是32个bit位
	{
		if (((n >> i) & 1) == 1)
			count++;
	}

这段代码使用一个循环来检查整数 n 的二进制表示中值为 1 的位的数量。 具体来说,循环从 0 迭代到 31 。对于每次迭代 i ,首先将 n 向右移动 i 位,然后与 1 进行按位与操作。如果结果为 1 ,说明 n 右移 i 位后的最低位是 1 ,此时就将计数器 count 的值增加 1 。当循环结束时,count 中存储的就是 n 的二进制表示中 1 的个数。

完整代码:

#include <stdio.h>
int main()
{
	int n = 0;
    scanf("%d",&n);
	int count = 0;//二进制中1的个数
	for (int i = 0; i < 32; i++)//一个整型是4个字节,一个字节8个bit,这里的32就是32个bit位
	{
		if (((n >> i) & 1) == 1)
			count++;
	}
	printf("%d\n", count);
	return 0;
}

从上面代码,我们可以发现一些问题,就是不管所求数的二进制中有几个1,都需要循环32次

我们可以修改一下

法二:

int n = 13

表达式n = n & (n-1)

13的二进制序列:1101

n = n-1
第一组n和n-1
1101 --n
1100 --n-1
1100 --新的n
将新的n与原来相比,可以看到少了一个1,且是最后一位
第二组n和n-1
1100 --新的n
1011 --n-1
1000 --新的n
与第二个n相比,可以看到最右边的1又没了
第三组n和n-1
1000 --新的n
0111 --n-1
0000 --新的n
与上一个n对比,1又消去了。

从上面的例子,我们应该也能看出表达式n = n & (n-1)的作用:让n的二进制序列中最右边的1消失

n = n & (n-1)表达式每执行一次,就会去掉一个1,知道n中的1全部被去掉为止,因此,我们可以通过表达式进行的次数,来计算n二进制序列中有几个1

代码展示:

#include <stdio.h>
int main()
{
	int n = 0;
    scanf("%d",&n);
	int count = 0;//二进制中1的个数
	while(n){
      n = n & (n-1);
      count++;}  
	printf("%d\n", count);
	return 0;
}

该程序的好处是不会产生额外的循环,n的二进制序列中有几个1,就循环几次,没有就不循环。

 

三、按位或:| 按位取反:~

或运算:有1为1,全0为0

应用:将13的二进制序列的第5位修改位1,然后再改回0

13的二进制序列:00000000000000000000000000001101
将第5位置改为1:00000000000000000000000000011101
再将第5位改回0 :00000000000000000000000000001101

00000000000000000000000000001101
00000000000000000000000000010000
或结果:
00000000000000000000000000011101

那么00000000000000000000000000010000该怎么得到呢?

我们可以将1的二进制序列通过左移操作符向左移动4位 (1<<4)

这样就可以得到想要的结果了

代码展示:

#include <stdio.h>
int main()
{
	int n = 13;
	n |= (1 << (5-1));//将第5位0改为1
	printf("%d\n", n);	
	return 0;
}

那么我们该怎么改回去呢?

这里我们就要用到&和~了

因此,代码展示:

#include <stdio.h>
int main()
{
	int n = 13;
	n |= (1 << (5-1));//将第5位0改为1
	printf("%d\n", n);	//29
	n &= (~(1 << (5 - 1)));//将第5位改回来
    printf("%d\n", n);//13
	return 0;
}


本篇文章到这里就结束了,期待你们的下次到来!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1964531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker Compose部署项目+使用

目录结构 - suggestion/- backend/ # 我的后端项目- app.py- other_files/- docker-compose.yml- Dockerfile- requirements.txt获得requirements.txt 命令行输入&#xff1a;pip list --formatfreeze > requirements.txt 因为使用 pip freeze > requirements.txt 导出…

创建了Vue项目,需要导入什么插件以及怎么导入

如果你不知道怎么创建Vue项目,建议可以看一看这篇文章 怎么安装Vue的环境和搭建Vue的项目-CSDN博客 1.在idea中打开目标文件 2.系在一个插件Vue.js 3.下载ELement UI 在Terminal中输入 # 切换到项目根目录 cd vueadmin-vue # 或者直接在idea中执行下面命令 # 安装element-u…

漏洞打靶-tomato

这是一个很有意思的靶场&#xff0c;靶机的安装过程请参考我的文章“漏洞打靶-hackme”&#xff0c;进入靶场后&#xff0c;迎面而来的就是一个大tomato&#xff0c;然后就无从下手了&#xff0c;查目录查不出来&#xff0c;sql注入也没地方注入 这时候我们可以用kali的nmap去查…

ARM学习(29)NXP 双coreMCU MCXN94学习

笔者来介绍一下NXP 双core板子 &#xff0c;新系列的mcxn94 1、MCX 新系列介绍 恩智浦 MCU 系列产品包括 Kinetis 、LPC 系列&#xff0c;以及 i.MX RT 系列&#xff0c;现在又推出新系列产品 MCX 产品&#xff0c;包括四个系列&#xff0c;目前已经发布产品的是 MCX N 系列。…

第十四天7.25(git)

1.git 1.git功能特性 1.克隆数据库版本&#xff1a;从服务器上克隆数据库本机上 2.提交代码&#xff1a;在本机上自己创建的分支上提交代码 3.合并分支&#xff1a;在本机上合并分支 4.拉取合并分支&#xff1a;新建一个分支&#xff0c;把服务器上最新的代码Fetch下来&…

微软工具合集 | Microsoft PowerToys v0.83.0

PowerToys是由微软开发的一款免费系统工具集&#xff0c;专为Windows 10和Windows 11系统设计。它提供了一系列高效实用的工具&#xff0c;旨在帮助用户提升操作系统的使用效率和个性化程度。PowerToys工具集深受系统管理员和高级用户的喜爱&#xff0c;通过集成多种工具&#…

XXE -靶机

XXE靶机 一.扫描端口 进入xxe靶机 1.1然后进入到kali里 使用namp 扫描一下靶机开放端口等信息 1.2扫描他的目录 二 利用获取的信息 进入到 robots.txt 按他给出的信息 去访问xss 是一个登陆界面 admin.php 也是一个登陆界面 我们访问xss登陆界面 随便输 打开burpsuite抓包 发…

《深入浅出WPF》学习笔记二.为对象属性赋值的三种方式

《深入浅出WPF》学习笔记二.为对象属性赋值的三种方式 WPF用户图形界面是树状结构 &#x1f446;wpf文档大纲 &#x1f446;winform文档大纲 wpf的用户图形界面是树状结构&#xff0c;与winform不同点在于&#xff0c;winform同样存在树状结构的控件(比如panel、gridcontrol等…

Wi-Fi、WLAN、Bluetooth、zigbee、蜂窝网络、4g5g、MQTT

为什么打开手机的WiFi连接&#xff0c;显示的是WLAN&#xff1f; 分清Wi-Fi、WLAN、Bluetooth、zigbee、蜂窝网络、4g5g、MQTT这些概念. 一、WLAN、WIFI、WAPI WLAN是利用无线通信技术在局部区域内构建的网络&#xff0c;家庭/办公室里的网络就是一个WLAN&#xff0c;WLAN是一…

【数据结构】Java实现二叉搜索树

二叉搜索树的基本性质 二叉搜索树&#xff08;Binary Search Tree, BST&#xff09;是一种特殊的二叉树&#xff0c;它具有以下特征&#xff1a; 1. 节点结构&#xff1a;每个节点包含一个键&#xff08;key&#xff09;和值&#xff08;value&#xff09;&#xff0c;以及指…

大语言模型中的提示隐私保护

大语言模型中的提示隐私保护 一、简介&#xff1a; 大语言模型&#xff08;LLM&#xff09; 拥有庞大的规模、预先训练的知识和卓越的性能&#xff0c;被广泛应用于各种任务。提示学习(prompt learning)和指令微调(instruction tuning) 是两种重要的使得大模型能理解具体任务…

决策树基础

概述 决策树是一种树型结构&#xff0c;其中每个内部结点表示在一个属性上的测试&#xff0c;每个分支代表一 个测试输出&#xff0c;每个叶结点代表一种类别。决策树学习采用的是自顶向下的递归方法&#xff0c;其基本思想是以信息熵为度量构造一棵熵值下降最快的树&#xff…

自学Java第16Day

学习目标&#xff1a;面向对象进阶 学习内容&#xff1a;Object、Objects、BigInteger、BigDecimal、正则表达式 学习时间&#xff1a;下午 3 点-下午 6 点 学习产出&#xff1a; 1. Object类 1.1 概述 查看API文档&#xff0c;我们可以看到API文档中关于Object类的定义如下&…

【SpringBoot3】场景整合(实战)

0 环境准备 0.0 云服务器 阿里云、腾讯云、华为云 服务器开通&#xff1b; 按量付费&#xff0c;省钱省心 安装以下组件&#xff1a;docker、redis、kafka、prometheus、grafana 下载windterm&#xff1a; https://github.com/kingToolbox/WindTerm/releases/download/2.5…

React-Native 宝藏库大揭秘:精选开源项目与实战代码解析

1. 引言 1.1 React-Native 简介 React-Native 是由 Facebook 开发的一个开源框架&#xff0c;它允许开发者使用 JavaScript 和 React 的编程模型来构建跨平台的移动应用。React-Native 的核心理念是“Learn Once, Write Anywhere”&#xff0c;即学习一次 React 的编程模型&am…

《LeetCode热题100》---<5.普通数组篇六道>

本篇博客讲解LeetCode热题100道普通数组篇中的六道题 第一道&#xff1a;最大子数组和&#xff08;中等&#xff09; 第二道&#xff1a;合并区间&#xff08;中等&#xff09; 第一道&#xff1a;最大子数组和&#xff08;中等&#xff09; 法一&#xff1a;贪心算法 class So…

文件上传漏洞--之upload-labs靶场(第1关到第5关)专栏更新ing.....

第一关&#xff1a; 第一步&#xff1a;新建一个木马文件muma.php 第二步&#xff1a;在木马文件中写入一句话木马访问php主页 <?php eval(phpinfo());?> ​ 第三步&#xff1a;直接上传试一下 现上传一个png格式文件查看一下 然后上传一句话木马文件的&#xff0c;…

C:图案打印

引言 本篇文章讲了一些常见的图形编程题&#xff0c;并总结了一些规律。 1、打印空心正方形 1.1 代码展示&#xff1a; #include<stdio.h> int main() {int a 0;//边长初始化scanf("%d", &a);//输入边长的值{int i 0;for (i 0; i < a; i)//控制行…

面试经典算法150题系列-数组/字符串操作之多数元素

序言&#xff1a;今天是第五题啦&#xff0c;前面四题的解法还清楚吗&#xff1f;可以到面试算法题系列150题专栏 进行复习呀。 温故而知新&#xff0c;可以为师矣&#xff01;加油&#xff0c;未来的技术大牛们。 多数元素 给定一个大小为 n 的数组 nums &#xff0c;返回其…