c语言常用操作符(2)

news2024/11/24 2:30:36

 1.移位操作符

移位操作符分为<<左移操作符和右移操作符>>
注:移位操作符的操作数只能是整数,同时移位操作符移动的是存储在内存中的二进制位(也就是补码

同时移位操作符不要移动负数位,这个是标准未定义的。

1.<<操作符

移位规则:左边抛弃、右边补0

例1
#include<stdio.h>
int main()
{
  int a=10;
  int b=a<<1;
  printf("a=%d\n",a);
  printf("b=%d\n",b);

 return 0;
}

由于a为正整数,所以补码与原码相同 

 所以b输出结果为20

例2 
#include<stdio.h>
int main()
{
	int a = -1;
	int b = a << 1;
	printf("a=%d\n", a);
	printf("b=%d\n", b);

	return 0;
}

由于a为负整数,所以补码等于原码取反加一

所以输出b输出结果为-2
 由以上例1与例2可以发现左移操作符有乘2的效果

 2.>>操作符

在右移操作符不同于左移操作符,右移操作符有两种运算
1. 逻辑右移:左边用0填充,右边丢弃
2. 算术右移:左边用原该值的符号位填充,右边丢弃

 例1
#include<stdio.h>
int main()
{
	int a = -1;
	int b = a >> 1;
	printf("a=%d\n", a);
	printf("b=%d\n", b);

	return 0;
}

 

所以算数右移b等于-1,逻辑右移b等于一个很大的正整数 

右移是采取算数右移还是逻辑右移是取决于编译器的 通常采取的都是算数右移
在vs中采取的也是算数右移

例2
#include<stdio.h>
int main()
{
	int a = 10;
	int b = a >> 1;
	printf("a=%d\n", a);
	printf("b=%d\n", b);

	return 0;
}

 以上代码输出结果为

通过以上代码可以发现右移有除2的效果 

2.位操作符

位操作符有:
&  按位与
|    按位或
^   按位异或
~   按位取反

注:位操作符的操作数必须是整数,同时位操作符是对存储在内存中的二进制位(也就是补码进行运算

在这不要将&和|与之前讲到的&&和||混淆 &&和||关注的是操作符两端的真假 &和|关注的是操作符两端的二进制序列

1.& 按位与

#include<stdio.h>
int main()
{
	int a = -7;
	int b = 6;
	int c = a & b;
	printf("c=%d\n", c);

	return 0;
}

在以上代码中a&b  首先我们知道&是对操作数在内存中存储的二进制位进行运算,所以先将a和b的补码表示出来如下所示

按位与操作符中两个操作数对应二进制位有0则为0,俩个都为1时,才为1 

所以就可得出c的补码

 最终c的结果为0
运行程序验证以上运算

2.|  按位或

#include<stdio.h>
int main()
{
	int a = -7;
	int b = 6;
	int c = a | b;
	printf("c=%d\n", c);

	return 0;
}

将此先的代码再使用一遍,而这时将c=a | b 

 在按位或操作符中两个操作数对应二进制位有1则为1,俩个都为0时,才为0

所以就可得出c的补码

 最终c的结果为-1
运行程序验证以上运算

3.^   按位异或

#include<stdio.h>
int main()
{
	int a = -7;
	int b = 6;
	int c = a ^ b;
	printf("c=%d\n", c);

	return 0;
}

在以上代码中用到了按位异或操作符,要得到c的结果首先要知道^的计算逻辑
按位异或操作符中两个操作数对应二进制位不同则为1,俩个相同时,才为0
 

所以最终c输出结果为-1
运行程序验证以上运算

4.~   按位取反  

按位取反操作符是将整数的二进制位全部取反 

#include<stdio.h>
int main()
{
	int a = -7;
	int b = 6;
	int c = a ^ b;
	int d = ~c;
	printf("d=%d\n", d);

	return 0;
}

例如在以上代码中对c按位取反 最终d输出结果为0

 运行程序验证以上运算

5.练习

练习1.一道面试题

不能创建临时变量(第三个变量),实现两个整数的交换。
 

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 0;;
	scanf("%d %d", &a, &b);
	 a = a ^ b;
	 b = a ^ b;
	 a = a ^ b;
	printf("a=%d b=%d",a,b);

	return 0;
}

要理解这种方法就要再了解一下^的一些特点 
1.a^a=0
2.a^0=a
3.a^b^c=a^c^b=b^a^c=b^c^a=c^a^b=c^b^a(异或是支持交换率)

来举一些例子让我们更好理解以上特点 

 例如:3^3操作符的二进制位都相同所以异或后都为0,所以最终3^3=0
            3^0操作符的二进制位都不同所以异或后都为原来3的二进制位,3^0=3
            1^2^3与3^2^1最终计算结果是相同的

在此之后我们再来理解以上代码

在b=a^b中的a=a^b,在最后的a=a^b中a=a^b b=a

运行程序验证以上运算

       

练习2

编写代码实现:求⼀个整数存储在内存中的二进制中1的个数 

我们知道要将一个数从十进制转换为二进制是需要通过不断整除2然后取出余数
所以我们可以想到以下方法来求一个数二进制中1的个数

#include<stdio.h>

int Number(int n)
{
 int count=0;
 while(a)
 {
  if(a%2==1)
  {
   count++;
  }
  a=a/2;
 }
 return count;
}

int main()
{

 int a=0;
 scanf("%d",&a);
 int n=Number(a);  
 printf("%d",n);

 return 0;
}

在以上方法会存在一个问题就是无法计算负数的二进制1的个数 这时有的读者会想到将形参用unsigned int,这种方法确实能解决问题 但有没有更好的方法呢?

#include<stdio.h>

int Number(int a)
{
 int count=0;
 int i=0;
 for(i=0;i<32;i++)
 {
  if((a>>i)&1)
  {
   count++; 
  }
 }
 return count;
}

int main()
{

 int a=0;
 scanf("%d",&a);
 int n=Number(a);  
 printf("%d",n);

 return 0;
}

 以上这种方法是将整数的二进制数的每一位都按位与1,若输出为1就count++;实现二进制位中1的计数 但这种方法也有一定的缺陷就是无论输入整数的二进制位中有几个1都需要将32位全部遍历一遍,这样会使得代码的效率不高 因此我们能否再设计一种方法来让统计出所有二进制1时就停止循环呢?

#include<stdio.h>

int Number(int a)
{
 int count=0;
 int i=0;
 while(n)
  {
   a=a&(a-1);
   count++; 
  }
 return count;
}

int main()
{

 int a=0;
 scanf("%d",&a);
 int n=Number(a);  
 printf("%d",n);

 return 0;
}

 要理解上面这种方法首先要了解n&(n-1)结果的特点

n&(n-1)能将整数的二进制位中去除一个1
例如当n=5时

所以利用这种方法就可以在二进制位1的个数为0时不再继续执行程序,提升了程序的效率

练习3

二进制位置0或者置1

 编写代码将13二进制序列的第5位修改为1,然后再改回0
13的2进制序列: 00000000000000000000000000001101
将第5位置为1后:00000000000000000000000000011101
将第5位再置为0:00000000000000000000000000001101

#include<stdio.h>

int main()
{

 int a=13;
 printf("%d",a);
  a=a|(1<<4);
 printf("%d",a);
  a=a&~(1<<4);
 printf("%d",a);
 return 0;
}

3.逗号操作符

 首先了解什么是逗号表达式
1 exp1, exp2, exp3, …expN

正如以上所示用逗号隔开的多个表达式就是逗号表达式,而这其中的逗号就是逗号操作符

逗号表达式中有一特点:从左向右依次执行并计算,整个表达式的结果是最后⼀个表达式的结果

int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?

 在以上代码中c的等号右边是一个逗号表达式,要从左向右计算得出的才是正确结果,因为前面表达式的计算可能会影响后面表达式的计算
a=b+10=12后b=a+1=13 所以最终c=13

逗号表达式同时还能在if;while等语句的判断部分使用,起到简化代码的作用

a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
//...
a = get_val();
count_val(a);
}

如果使用逗号表达式就可以简化为:

while (a = get_val(), count_val(a), a>0)
{
//业务处理
}

4.下标访问操作符、函数调用操作符

1. [ ] 下标引用操作符 

int arr[4]={1,2,3,4};
int n=arr[3];

arr[3]表示数组下标为3的元素是4 这里面的[]就是下标引用操作符 arr[3]中操作数arr和3 

由此可见 [ ]下标引用操作符也是双目操作符 

注:在int arr[4]中的[ ]是用来指定数组元素大小不是在访问数组的某个元素,所以不是下标引用操作符

2.函数调用操作符

#include<stdio.h>
int Add(int x,int y)
{
  return x+y;
}

int main()
{
int a=0;
scanf("%d %d",&a,&b);
printf("%d %d\n",a,b);
int n=Add(a,b);
printf("%d",n);
return 0;
}

在以上代码中库函数printf和自定义函数Add后的括号都是函数调用操作符
其中Add后()的操作数是Add ,3,5

那函数调用操作符至少有几个操作数呢?
答案是至少有一个,原因是在调用时候函数名不可省略,但参数可能为0

5. 结构成员访问操作符

但要描述一个复杂对象时单一的数据类型已经不足以实现,C语言为了解决这个问题,增加了结构体这种自定义的数据类型,让程序员可以自己创造适合的类型。

📌 结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:
标量、数组、指针,甚至是其他结构体。

1.结构的声明 

在结构体的声明要用到struct关键字
 

struct tag//tag的名字可是自定义的
{
member-list;//成员列表
}variable-list;//变量列表

例如用struct定义一个学生类型
 

struct Stu//学生类型
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

2.结构体变量的定义和初始化

变量的定义 

struct Stu//学生类型
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}s3,s4;

struct student s2;

int main()
{
 struct student s1;

 return 0;
}

正如以上所示变量的创建可以是全局变量也可以是局部变量,还可以在结构体声明的末端

 变量的初始化

struct Stu        //类型声明
{
char name[15];//名字
int age;//年龄
};

struct Stu s1 = {"zhangsan", 20};//初始化

struct Node
{
int data;
struct Stu p;
 int arr[4];
}n1 = {1,{"zhangsan", 20},{1,2,3,4},};//结构体嵌套初始化

struct Node n2 = {6,{"lisi", 19},{9,2,5,4},};//结构体嵌套初始化

结构成员访问操作符

结构体成员的直接访问是通过点操作符(.)访问的。
使用方式:结构体变量.成员名

#include<stdio.h>
struct Stu        //类型声明
{
char name[15];//名字
int age;//年龄
};

struct Stu s1 = {"zhangsan", 20};//初始化

struct Node
{
int data;
struct Stu p;
 int arr[4];
}n1 = {1,{"zhangsan", 20},{1,2,3,4},};//结构体嵌套初始化

struct Node n2 = {6,{"lisi", 19},{9,2,5,4},};//结构体嵌套初始化

int main()
{

printf("%d %s %d %d",n2.data,n2.p.name,n2.p.age,n2.arr[1]);

 return 0;
}

 代码运行结果

 

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

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

相关文章

凡尔码安全巡检卡替代传统纸质记录卡

建筑行业、物业管理、医院等行业的安全巡检的记录方式通常以&#xff1a;1、纸质记录&#xff1a;巡检人员使用纸质巡检表格&#xff0c;手动填写巡检时间、巡检区域、巡检发现的问题以及处理情况。这种方式简单直接&#xff0c;但可能存在信息记录不完整、易丢失等问题。 2、电…

Glowroot:Java应用的性能守护神,让监控变得既轻松又有趣!

Glowroot&#xff1a;Java应用的性能守护神&#xff0c;让监控变得既轻松又有趣&#xff01; 在这个快节奏的数字化时代&#xff0c;作为一名开发者&#xff0c;你是否曾因应用性能问题而夜不能寐&#xff1f;是不是常幻想有个超级英雄能在关键时刻挺身而出&#xff0c;帮你揪…

基于深度学习的人体关键点检测与姿态识别

文章目录 源码下载地址&#xff1a; 源码地址在视频简介中 深度学习人体关键点检测&#xff0c;姿态识别 界面效果&#xff1a; 界面代码&#xff1a; from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * f…

先经营好自己,才是成事最坚实的基础!做事要稳!

电影《教父》里有句著名的台词说&#xff1a;花半秒钟就能看透事物本质的人&#xff0c;和花一辈子也看不透事物本质的人&#xff0c;注定是截然不同的命运。而这所谓的“看透本质”&#xff0c;就是事物的底层逻辑。 底层逻辑是一种解决问题的思维模式。底层逻辑越坚固&#x…

SharePoint 使用renderListDataAsStream方法查询list超过5000时的数据

问题&#xff1a; 当SharePoint List里的数据超过5000时&#xff0c;如果使用常用的rest api去获取数据&#xff0c;例如 await this.sp.web.lists.getByTitle(Document Library).rootFolder.files.select(*, listItemAllFields).expand(listItemAllFields).filter(listItemA…

科技控必看!让你轻松成为机器人领域达人

科技控们注意了&#xff01;你是不是经常对机器人技术充满无限的好奇&#xff0c;却又因为缺乏合适的渠道而难以深入了解和亲身体验呢&#xff1f;别担心&#xff0c;BFT机器人&#xff0c;正是你探索机器人世界的绝佳之地&#xff01; 在这里&#xff0c;你将发现一个充满惊喜…

更高效环保!格力博重新定义“中高端”割草机

格力博&#xff08;江苏&#xff09;股份有限公司&#xff08;以下简称&#xff1a;格力博或公司&#xff09;作为全球新能源园林机械行业的领先企业&#xff0c;始终走在创新前沿。自2007年开始从事新能源园林机械的研发、设计、生产及销售&#xff0c;格力博始终践行绿色发展…

el-carousel走马灯页数回到第一页

我的走马灯是在一个弹窗里,包裹着一些button,切换到下一页时 关闭弹窗再打开弹窗还显示的是上次第二页位置 领导很不满意 1. 2.写在你打开弹窗或者关闭弹窗的位置 this.$refs.carousel && (this.$refs.carousel.activeIndex 0); 解释一下: this.$refs.carousel: thi…

FPGA第二篇,FPGA与CPU GPU APU DSP NPU TPU 之间的关系与区别

简介&#xff1a;首先&#xff0c;FPGA与CPU GPU APU NPU TPU DSP这些不同类型的处理器&#xff0c;可以被统称为"处理器"或者"加速器"。它们在计算机硬件系统中承担着核心的计算和处理任务&#xff0c;可以说是系统的"大脑"和"加速引擎&qu…

Go 语言基础之指针、复合类型【数组、切片、指针、map、struct】

1、数组 特别需要注意的是&#xff1a;在 Go 语言中&#xff0c;数组长度也是数组类型的一部分&#xff01;所以尽管元素类型相同但是长度不同的两个数组&#xff0c;它们的类型并不相同。 1.1、数组的初始化 1.1.1、通过初始化列表{}来设置值 var arr [3]int // int类型的数…

String类 StringBuffer 类 StringBuilder 类

String 类的理解和创建对象 1&#xff0c;String 对象用于保存字符串&#xff0c;也就是一组字符数列2&#xff0c;字符串常量对象是用双引号括起的字符序列。例如&#xff1a;“你好”、“12.97”、“boy”等3&#xff0c;字符串的字符使用Unicode字符编码&#xff0c;一个字…

【喜讯】热烈祝贺蒋林华教授当选玻利维亚国家科学院院士

2024年4月29日&#xff0c;人工智能领域知名专家蒋林华教授受邀出席北京中关村论坛侨海创新发展平行论坛&#xff0c;在玻利维亚国家参议院参议员马马尼纳瓦罗希拉里昂&#xff08;Mamani Navarro Hilarion&#xff09;和拉莫斯索帕萨桑托斯&#xff08;Ramos Socpaza Santos&a…

Linux学习笔记:信号

信号 在Linux中什么是信号信号的产生方式硬件产生的信号软件产生的信号异常产生的信号 进程对信号的处理信号的保存信号方法更改函数signal信号处理的更改恢复默认信号忽略 信号的管理信号集 sigset_t对信号集的操作 信号的捕捉过程 在Linux中什么是信号 在 Linux 系统中&…

使用ROW_NUMBER()分组遇到的坑

1、再一次清洗数据时&#xff0c;需要过滤重复数据&#xff0c;使用了ROW_NUMBER() 来分组给每组数据排序号 在获取每组的第一行数据 with records as(select cc.F_Id as Id,REPLACE(cc.F_CNKITitle,char(10),1) as F_CNKITitle,REPLACE(REPLACE(cc.F_Special,专题&#xff1…

从封号之痛出发:探索自养号测评,助力eBay卖家破局重生

在跨境电商的浪潮中&#xff0c;eBay作为知名的电商平台&#xff0c;吸引了众多卖家前来拓展业务。然而&#xff0c;近年来不少卖家反映&#xff0c;因环境问题导致eBay账号被封号&#xff0c;成为他们业务发展的痛点。为此&#xff0c;本文将探讨如何通过自养号测评&#xff0…

学习方法的重要性

原贴&#xff1a;https://www.cnblogs.com/feily/p/13999204.html 原贴&#xff1a;https://36kr.com/p/1236733055209095 1、 “一万小时定律”的正确和误区 正确&#xff1a; 天才和大师的非凡&#xff0c;不是真的天资超人一等&#xff0c;而是付出了持续不断的努力&…

QLineEdit 最右侧添加按钮

如果采用QLineEdit + QPushButton的方式的话,无法将按钮放到QLineEdit的输入框内部,所以下面的方法可以将按钮放到QLineEdit内部的最右侧,效果: 代码如下: QLineEdit* editor = new QLineEdit(parent); QToolButton* btn = new QToolButton; btn->setText("...&q…

【操作系统】进程与线程概念基础知识

进程与线程概念基础知识 进程进程的概念进程控制块进程状态进程三状态模型挂起进程模模型进程的上下文切换进程控制 线程为什么引入线程线程的概念线程与进程的比较线程的上下文切换线程的实现 进程 进程的概念 1. 进程的定义&#xff1a; 进程是指一个具有一定独立功能的程序…

航空电子FC节点卡, FC交换机,主要采用LC或MPO光纤接口形式

FC节点卡主要采用LC或MPO光纤接口形式&#xff0c;可以作为4/2个独立端口使用&#xff0c;也可以作为2对/1对冗余端口使用&#xff0c;支持1.0625Gbps、2.125Gbps、4.25Gbps、8.5Gbps通信速率。节点卡完全遵循FC-LS&#xff0c;FC-FS&#xff0c;FC-AE-ASM、FC-AE-1553B等FC光纤…

特斯拉擎天柱机器人:工厂自动化的未来

随着技术的进步&#xff0c;工业自动化已经逐步进入了一个新的纪元。特斯拉最近公布的擎天柱机器人Optimus的演示&#xff0c;不仅仅展示了一个高科技机器人的能力&#xff0c;更是向我们揭示了未来工厂的可能性。 特斯拉擎天柱机器人的功能展示 马斯克在最新的演示中向我们展…