【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符

简介: 【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符

前言

今天给大家带来的是操作符详解,由于这部分的内容比较多,可能会分成几部分讲,今天带来的是第一部分的内容,废话不多说,咱们开始吧!


一.操作符的分类

操作符大致分为以下几种

算术操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

下标引用、函数调用和结构成员

咱们还是先画个图来说明,具体的再一个一个介绍用法及使用场景

4cb123c49a974bd385ab4e4351c73421.png

二.算数操作符

   +   -  *  /  %

1.除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。

2.对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。

3.% 操作符的两个操作数必须为整数。返回的是整除之后的余数。

我们来通过一段代码理解一下:

#include<stdio.h>
int main()
{
  int r = 7 / 2;
  printf("%d\n", r);
  double d = 7 / 2;
  printf("%lf\n", d);//3.5?
  double d1 = 7.0 / 2.0;
  printf("%lf\n", d1);//3.5?
  return 0;
}

运行结果

19ced30b55384b9bb1f6931c6f161a8b.png

大家可能对打印的第一个数字和第三个数字都没什么疑问,唯一有问题的就是为什么第二个后面的小数部分被省去了,接下来我来讲讲原因

我们可以看到7和2都是整数,那么执行的就是整数除法,在整形中是不存在小数的,因此小数点后面的部分会被直接舍去,此时我们又把7/2得到的3赋给一个浮点型的d,打印出来是要保留小数后面的几位的,因此打印出来的才是屏幕上的结果

总结:

当你想要进行浮点数除法时,除号两边的数得至少有一个浮点型!!!

三.移位操作符

<< 左移操作符
>> 右移操作符
注:移位操作符的操作数只能是整数。

在讲这方面内容之前,先给大家简单的补充一些数据在内存中存储的知识,方便大家下面更好的理解,如果你想更具体的了解这方面的知识,不妨去看看我的这两篇博客,以下是链接:

【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(1)?

【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(2)?

整型在内存中是以二进制的形式存储的,而内存中存储的是补码,并且是倒着存的。


现在我来具体解释一下上面这段话。


1.二进制表示的三种形式

二进制在内存中表示形式分别是原码,反码,补码。

其中,数据在内存中是以二进制补码的形式进行存储的

以下面的代码说明

int main()
{
  int num  = 10;//创建一个整型变量,叫num,这时num向内存申请4个字节来存放数据
  //4个字节-32比特位
  //00000000000000000000000000001010-原码
  //00000000000000000000000000001010-反码
  //00000000000000000000000000001010-补码
  int num2 = -10;//
  //10000000000000000000000000001010 - 原码
  //11111111111111111111111111110101 - 反码
  //11111111111111111111111111110110 - 补码
  return 0;
}

十进制数据的二进制表现形式就是原码,原码最左边的一个数字就是符号位,0为正,1为负。

对于正数而言,原码反码补码三者相同,对于负数而言,反码为原码符号位不变,其他位取反(1变为0,0变为1)

对于负数而言,补码为反码+1。

2.左移操作符 <<

移位规则

左边抛弃,右边补零

注意,以下我们所说的移位,移动的都是补码的二进制序列

int main()
{
  int num = 10;//创建一个整型变量,叫num,这时num向内存申请4个字节来存放数据
  //4个字节-32比特位
  //00000000000000000000000000001010-原码
  //00000000000000000000000000001010-反码
  //00000000000000000000000000001010-补码
  int b=num << 1;
  //00000000000000000000000000010100-补码
  printf("%d\n", num);
  printf("%d\n", b);
  return 0;
}

bbe02f08ea7a42b0883a9de8e36e5953.png

注意,移位操作并不会改变原来变量的大小!!

3.右移操作符 >>

移位规则:

首先右移运算分两种:

1. 逻辑移位

左边用0填充,右边丢弃

2. 算术移位

左边用原该值的符号位填充,右边丢弃

int main()
{
  int num = 10;
  //逻辑右移 左边用0填充,右边丢弃
  //00000000000000000000000000001010-补码
  int b=num >> 1;
  //00000000000000000000000000000101-补码
  printf("%d\n", num);
  printf("%d\n", b);
  //算数右移 左边用原该值的符号位填充,右边丢弃
  int num1 = -1;
  //10000000000000000000000000000001-原码
  //11111111111111111111111111111110-反码
  //11111111111111111111111111111111-补码
  int c = num1 >> 1;
  printf("%d", c);
  return 0;
}

C语言没有明确规定是逻辑右移还是算术右移,但是一般编辑器采用的都是算术右移


如图可见,我们当前编译器采用的是逻辑右移,否则符号位应该变为0打印出来的应该是一个正数。

4.错误的写法

另外,要注意这种写法:

int main()
{
  int a = 5;
  int b = a >> -2;//标准未定义行为
  return 0;
}

有些人可能脑子一抽,突然想到,我右移一个负数不就是左移吗?

注意:对于移位运算符,不要移动负数位,这个是标准未定义行为!!

四.位操作符

位操作符有:

 & //按位与
 | //按位或
 ^ //按位异或

注:他们的操作数必须是整数。

以下位操作符对应操作的仍然是二进制补码

1.& 按位与

& 按位与 ---- 对应二进制位有0则为0,两个同时为1,才是1

int main()
//{
//  int a = 3;
//  //00000000000000000000000000000011 - 补码
//  int b = -5;
//  //10000000000000000000000000000101
//  //11111111111111111111111111111010
//  //11111111111111111111111111111011 - 补码
//  //
//  int c = a & b;
//  //& -- 对应二进制位有0则为0,两个同时为1,才是1
//  //00000000000000000000000000000011
//  //11111111111111111111111111111011
//  //00000000000000000000000000000011 - 补码
//  //
//  printf("%d\n", c);//3
//
//  return 0;
//}

504517c733e046a788b9a2ccf10e73dc.png


2.| 按位或

| 按位或 ---- 对应的二进制位有1则为1,两个同时为0才是0


int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101
  //11111111111111111111111111111010
  //11111111111111111111111111111011 - 补码
  //
  int c = a | b;
  //| - 按(2进制)位或 - 对应的二进制位有1则为1,两个同时为0才是0
  //00000000000000000000000000000011
  //11111111111111111111111111111011
  //11111111111111111111111111111011 - 补码
  //11111111111111111111111111111010
  //10000000000000000000000000000101 - -5
  printf("%d\n", c);//3
  return 0;
}


288983a291384acebea99867df53f9c3.png

3.^ 按位异或

^ 按位异或 ----对应的二进制位相同为0,相异为1


int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101
  //11111111111111111111111111111010
  //11111111111111111111111111111011 - 补码
  //
  int c = a ^ b;
  //^ - 按二进制位异或 -对应的二进制位相同为0,相异为1
  //00000000000000000000000000000011
  //11111111111111111111111111111011
  //11111111111111111111111111111000 - 补码
  //11111111111111111111111111110111
  //10000000000000000000000000001000 - -8
  printf("%d\n", c);//3
  return 0;
}

00f98d7a87334c1f81342942aee7ae46.png

4.位操作符应用实例

看了上面的内容,可能有些人会有疑问,这些位操作符具体都有啥用呢?

以下我们来通过几个例子说明:

1.我们先来看一个简单的例子:

int main()
{
int num1 = 1;
int num2 = 2;
num1 & num2;
num1 | num2;
num1 ^ num2;
return 0;
}

上面的这段代码a,b,c的结果是多少?

f29cecfee6dc4204a9bd7638ebdbdff6.png

很简单吧?遇到这种问题一定不要偷懒,画图是最好的解决方法!

2.在不创建临时变量(第三个变量)的情况下,实现两个数的交换。

这其实是某公司的一个面试题,如果你能理解上面所讲的内容并学会应用,其实并不复杂。

实现代码如下:

//在不创建临时变量(第三个变量)的情况下,实现两个数的交换。
int main()
{
  int a = 10;
  00000000000000000000000000001010--10的补码
  int b = 20;
  00000000000000000000000000010100--20的补码
  a = a ^b;
  b = a ^ b;
  a = a ^ b;
  printf("a=%d b=%d", a, b);
  return 0;
}

48f9c8b223b44097acbaf047139480d3.png


成功实现我们的目标,可是为什么呢?

下面我来解释一下,如果你是基础不是特别好的初学者的话,这里还是建议自己先画图感受一下哦!

  a = a ^b;
  //00000000000000000000000000001010--a
  //00000000000000000000000000010100--b
  //00000000000000000000000000011110--a=a^b

此时a已经变成了a ^b

  b = a ^ b;
  //00000000000000000000000000010100--b
  //00000000000000000000000000011110--a=a^b
  //00000000000000000000000000001010-b=a^b    

此时的b已经与a完成交换变成10了

a = a ^ b;
  //00000000000000000000000000011110--a=a^b
  //00000000000000000000000000001010-b=a^b 
  //00000000000000000000000000010100 a=a^b a=20

最后一次异或,把b的值交换给a

逐步分析这段代码是不是就清晰多了?

总结

今天的内容暂时到这里就结束了,我们今天讲了有关算数操作符,移位操作符和位操作符的应用,如果你还有所困惑不妨自己动手实操一下,这方面的知识是稍微有点抽象,需要咱们反复的练习熟悉起来才行。

以上就是关于操作符的第一部分内容,后面其他的操作符应用详解会在近期分批次更新,敬请期待!!

好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!


**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**


20fa3306e76244de9879742c165c792a.gif

目录
相关文章
|
2天前
|
存储 编译器 程序员
C语言的模型玩具:结构体的使用以及操作符优先级
C语言的模型玩具:结构体的使用以及操作符优先级
|
3月前
|
C语言
C语言操作符逻辑与,逻辑或面试真题(2)
C语言操作符逻辑与,逻辑或面试真题(2)
|
3月前
|
程序员 C语言 C++
C语言操作符if语句好习惯 详解分析操作符(详解4)
C语言操作符if语句好习惯 详解分析操作符(详解4)
|
3月前
|
C语言
操作符详解(3)C语言复合赋值操作符单目操作符
操作符详解(3)C语言复合赋值操作符单目操作符
|
3月前
|
C语言
C语言操作符详解(3)初始化和赋值操作符h
C语言操作符详解(3)初始化和赋值操作符h
|
3月前
|
C语言
C语言的详解操作符(2)之取余操作符
C语言的详解操作符(2)之取余操作符
|
3月前
|
存储 编译器 C语言
c语言进阶部分详解(指针初阶)
c语言进阶部分详解(指针初阶)
24 0
|
2月前
|
存储 小程序 编译器
learn_C_deep_10 深刻认识C语言重点操作符(上)
learn_C_deep_10 深刻认识C语言重点操作符
|
2天前
|
存储 程序员 C语言
“探索C语言操作符的神秘世界:从入门到精通的全方位解析“
“探索C语言操作符的神秘世界:从入门到精通的全方位解析“
|
7天前
|
存储 编译器 C语言
C语言之操作符详解篇
C语言之操作符详解篇
41 1