【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

目录
相关文章
|
3月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
74 0
|
3月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
257 0
|
26天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
34 10
|
1月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
160 1
|
1月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
172 0
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
7天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
22 6
|
20天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
|
25天前
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
53 7
|
25天前
|
存储 编译器 程序员
【c语言】函数
本文介绍了C语言中函数的基本概念,包括库函数和自定义函数的定义、使用及示例。库函数如`printf`和`scanf`,通过包含相应的头文件即可使用。自定义函数需指定返回类型、函数名、形式参数等。文中还探讨了函数的调用、形参与实参的区别、return语句的用法、函数嵌套调用、链式访问以及static关键字对变量和函数的影响,强调了static如何改变变量的生命周期和作用域,以及函数的可见性。
29 4