当前位置: 首页 > news >正文

操作符详解(上篇)

前言

小伙伴们大家好,随着对c的不断学习今天我们将来学习操作符。在初始c语言中也介绍过操作符但也只是点到即可,今天我们将详细了解操作符。

操作符分类:

算术操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

下表引用,函数调用和结构成员

算术操作符

算术操作符都有哪些呢?让我们一起来看看吧。算术操作符包括:+ - * / %.在数学中乘号是X,但是在c语言中乘号是用*来表示的。同样的还有除号,也与数学中的写法不一样。同时还要注意的两个点,第一当除号两端都是整数时执行的是整数除法结果也是整数;除号有一端是小数时执行小数除法,所得的结果也是小数的形式。

第二个值得注意的点就是%,%是取模也被称之为取余。%的两端只能是整数不能是小数

当%的两端有一端是小数时,编译器会报错并提示有小数的一端非法

位移操作符

操作符移动的是二进制位,此时不得不先提整数的二进制表示形式。以int a = -3为例,int 是4个字节一个字节是八个比特位,所以此时a的二进制位有32位10000000000000000000000000000000011。整数的二进制表示形式有三种:原码,反码,补码。还是以a为例,此时a的原码为10000000000000000000000000000000011。反码:最高位不变,其余位进行按位取反,此时a的反码为11111111111111111111111111111100,。补码:在反码的基础上进行加1,此时a的补码为11111111111111111111111111111101.需要注意的是,正整数的原码反码补码都是一样的,而负整数的原码反码补码需要进行计算得出。可能有小伙伴要问了为啥我们非得要补码呢?原码不可以直接用吗?我们要求补码,是因为整数在内存中的存储是以补码的形式。

左移操作符<<

左移操作符移的是二进制的是二进制位

a的二进制位是000000000000000000000000000000011,把a的二进制位向左移一格,舍弃左边,右边补0,此时我们会得到b的二进制位000000000000000000000000000000110,b的值为6.上代码

简单归纳,左移操作符的使用方法是舍弃左边,右边补0.

右移操作符>>

左移操作符移的是二进制位,同样右移操作符移的也是二进制位。不过右移操作符分为两种:一种是逻辑右移,另一种是算术右移。逻辑右移:右边丢弃,左边直接用0填充。算术右移:右边丢弃,左边原来的符号位填充。在代码中是使用算术右移还是逻辑右移,这是由编译器决定的。不过一般都是使用算术右移。

从这里可以看出实现的是算术右移。那我们来分析一下倘若进行逻辑右移时又会有什么不同呢?让我们一起来看看吧。a=-3,其二进制位原码为10000000000000000000000000000011,反码:最高位不变,其余位进行按位取反得到11111111111111111111111111111100,补码:在反码的基础上加一得到11111111111111111111111111111101。当a按照算术右移来移动已为时,右边丢弃左边直接补0得到补码为:01111111111111111111111111111110 。补码减一取反得到原码:00000000000000000000000000000010此时得到a>>1的值为2.

不管是左移操作符还是右移操作符移动的都是整数,一定不能是小数。同时移动整数时一般移动的都是正整数。直接上代码来看看效果吧。当a左移的是一个负数时编译器会发出警告,同时运行结果是一个负数

这里我们需要注意,位移操作符移动的是整数且是正整数

位操作符

位操作符的分类:按位与&,按位或|,按位异或^。不管是按位与还是按位或还是按位异或中的位都是二进制位

按位与&

按位与简单来说就是,有0则0.用代码来理解吧

按位或|

按位或简单来说:有1则为1.依旧是用代码来理解吧

按位异或^

按位异或的使用方法:相同为0相异为1.依旧是用代码理解

来利用按位异或的知识来写一道题吧。题目要求为不使用临时变量来交换两个变量的值。

在之前的学习中交换两个变量的值我们会通过使用临时变量。但这题的要求是不使用临时变量。第一种解决方法

#include<stdio.h>
int main()
{int a = 3;int b = 5;printf("a=%d b=%d\n", a, b);a = a + b;//a=8b = a - b;//b=8-3=5;a = a - b;//a=8-5=3;printf("a=%d b=%d\n", a, b);return 0;
}

此时达到了交换变量值的目的,但是这种代码存在问题。当a和b的值非常大时,a+b的结果容易溢出。这种方法还是不太好。

第二种方法利用按位异或来进行解决

#include<stdio.h>
int main()
{int a = 3;int b = 5;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;
}

利用按位异或,可以达到交换变量的效果。那可能又有小伙伴要问了,为啥会这样呢?接下来就让我们一起来分析分析吧

a的二进制位00000000000000000000000000000011

b的二进制位00000000000000000000000000000101

第一次按位异或得到a的值,这个值作为交换变量值的桥梁

a^b的结果为:00000000000000000000000000000110,a=a^b,此时a的值为6

再进行按位异或得到b的值

b=a^b::00000000000000000000000000000011 ,b的值为3

最后进行一次按位异或得到a的值

a=a^b:00000000000000000000000000000101,a的值为5.

赋值操作符

赋值操作符=,这里要注意区别与==。=是赋值操作符,==是判断相等。赋值操作符可以改变变量之前的值

   double salary = 10000.0;salary = 20000.0//使用赋值操作符进行赋值int weight = 110;weight = 90;//对体重不满意就可以赋值

复合赋值

+= : a= a+b;可以改成a+=b;

-= : a=a-b可以改成a -= b;

/=: a=a/b可以改为a/=b

%=: a=a%b可以改为a%=b;

>>=: a=a>>1改为a>>=1

<<+: a=a<<=1改为a<<=1

&= : a=a&b改为a&=b;

|= : a=a|b改为a|=b;

^=: a=a^b改为a^=b;

单目操作符

单目操作符的分类

!逻辑反操作符,++自增操作符,--自减操作符,&取地址操作符,*解引用操作符,~对一个二进制位进行按位取反,+正值,-负值,sizeof操作数类型大小(单位为字节),(类型)强制类型转化

!逻辑反操作符

!逻辑反操作符,例如a=1为真是,那么!a为假。倘若b=0时为假,那么!b为真

++自增操作符

++自增操作符分为前置++和后置++。前置++先加加再使用;后置加加,先使用再加加。直接上代码来康康它们的区别吧

int main()
{int a = 10;int b = a++;printf("a=%d,b=%d ", a, b);//a=11,b=10return 0;
}
int main()
{int a = 10;int b = ++a;printf("a=%d,b=%d ", a, b);//a=11,b=11return 0;
}

--自减操作符

--自减操作符也分为前置--和后置--.前置减减先减减再使用;后置减减,先使用再减减。上代码

int main()
{int a = 10;int b = --a;printf("a=%d,b=%d ", a, b);//a=9,b=9return 0;
}
int main()
{int a = 10;int b = a--;printf("a=%d,b=%d ", a, b);//b=10,a=9return 0;
}

&取地址操作符

&取地址操作符可以取出变量或者数组的地址,然后把地址放在指针变量中存储起来。

int main()
{int a = 10;int * pa = &a;printf("%p ", pa);return 0;
}

此时可以通过pa找到a的地址

int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9 };printf("%p ", &arr);return 0;
}

*解引用操作符

解引用操作符通常和取地址操作符搭配使用

int main()
{int a = 10;int* pa = &a;*pa = 20;printf("%d ", a);return 0;
}

把a的地址放在指针变量pa中,再通过解引用操作符对pa进行解引用操作。*pa就相当于是a

~对二进制位进行按位取反

直接上代码来康康吧

int main()
{int a = -3;//原码:10000000000000000000000000000011;//反码:11111111111111111111111111111100//补码:11111111111111111111111111111101a = ~a;  //~a;000000000000000000000000000000010printf("%d ", a);return 0;
}

sizeof操作数类型的大小

sizeof用来计算所占空间大小单位为字节,不但可以计算变量的大小还可以计算数组大小。让我们一起来看看代码吧

int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof(int));int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };printf("%d\n", sizeof(arr));printf("%d\n", sizeof(int[10]));return 0;
}

(类型)强制类型转化操作符

这种出现了一个警告,从double转化到int 可能丢失数据。此时有两种解决办法:第一种将int a 改为double a.把a的类型改为浮点型。第二种方法在10.0/3之前放一个(int)将结果转化为整形

以上就是操作符详解的上篇,欲知下事如何请听下回分解。操作符详解下篇正在准备中。

创作不易还望各位大佬们点赞,么么哒

http://www.lryc.cn/news/37.html

相关文章:

  • 采样电路的3个组成部分
  • ffmpeg硬解码与软解码的压测对比
  • 操作符——“C”
  • YSP的UI界面设计
  • 干货 | 什么是磁传感器?最常用的磁传感器类型及应用
  • 操作符(运算符)详解
  • 【LeetCode每日一题】【2023/2/9】1797. 设计一个验证系统
  • 计算机图形学:改进的中点BH算法
  • 【SQL开发实战技巧】系列(六):从执行计划看NOT IN、NOT EXISTS 和 LEFT JOIN效率,记住内外关联条件不要乱放
  • 十分钟利用环信WebIM-vue3-Demo,打包上线一个即时通讯项目【含音视频通话】
  • pandas——DataFrame基本操作(二)【建议收藏】
  • PostgreSQL查询引擎——General Expressions Grammar之restricted expression
  • 从某种程度上来看,产业互联网是一次对于互联网的弥补和修正
  • 【C#Unity题】1.委托和事件在使用上的区别是什么?2.C#中 == 和 Equals 的区别是什么?
  • FFmpeg5.0源码阅读——内存池AVBufferPool
  • Python学习------起步7(字符串的连接、删除、修改、查询与统计、类型判断及字符串字母大小写转换)
  • 雪花算法snowflake
  • Part 4 描述性统计分析(占比 10%)——上
  • Linux系统安全:安全技术和防火墙
  • 【干货】Python:turtle库的用法
  • 信息安全与网络安全有什么区别?
  • 花了5年时间,用过市面上95%的工具,终于找到这款万能报表工具
  • ESP32S3系列--SPI主机驱动详解(一)
  • 2023开工开学火热!远行的人们,把淘特箱包送上顶流
  • Intel x86_64 PMU简介
  • Vue (2)
  • ESP8266 + STC15基于AT指令通过TCP通讯协议获取时间
  • 谈谈Spring中Bean的生命周期?(让你瞬间通透~)
  • 如何将VirtualBox虚拟机转换到VMware中
  • 洞庭龙梦(开发技巧和结构理论集)