C语言基础(7)之操作符(1)(详解)

目录

1. 各种操作符介绍

1.1 操作符汇总表

2. 移位操作符

2.1 移位操作符知识拓展 —— 原码、反码、补码

2.2 移位操作符讲解

2.2.1 右移操作符 ( >> )

2.2.2 左移操作符 ( << )

3. 位操作符

3.1 & (按位与)

3.2 | (按位或)

3.3 ^ (按位异或)

3.4 按位异或的小技巧和测试题

4. 赋值操作符

5. 单目操作符

5.1 ! (逻辑反操作)

5.2 - (负值) 和 + (正值)

5.3 & (取地址操作符) 和 * (间接访问操作符)

5.4 sizeof 操作符

5.5 ~ (按位取反)

5.6 -- 和 ++

5.7 (类型)


        老铁们好呀,又到了讲C语言新知识的环节了,在前两篇文章中我们用C语言的基础知识给大家写了两个常见的游戏:三子棋小游戏和扫雷小游戏,不知道有没有激起大家对C语言的乐趣呢?那么今天我就给大家C语言中的操作符。
        如果大家没有实现过这两个小游戏,那下面给大家附上链接啦。
                三子棋游戏链接:C语言之三子棋游戏(附完整源码)
                扫雷游戏链接:C语言之扫雷游戏(附完整代码)

1. 各种操作符介绍

        在前面的文章中给大家简单的介绍过几种操作符,那么今天就用 代码+讲解 的形式给大家详细的介绍一下各种操作符,首先是给大家一个操作符的汇总表:

1.1 操作符汇总表

(1) 算术操作符: +    -    *    /    %(取模操作符(取余),只适用于整数运算)
注:除法有:整数除法(如:9/2)、 浮点数除法(需要保证除数和被除数中至少有一个数是浮点数,如9.0/4)。

      

(2) 移位操作符(移动的是二进制位): >>(右移)           <<(左移)

        

(3) 位操作符(操作的是二进制位):  &    ^    |

        

(4) 赋值操作符: =     +=     -=     *=     /=     &=    ^=    |=      >>=     <<=

        

(5) 单目操作符:!                   逻辑反操作
                           -                   负值
                          +                   正值
                          &                   取地址
                        sizeof              操作数的类型长度(以字节为单位)
                          ~                   对一个数的二进制按位取反
                           --                  前置、后置--
                         ++                  前置、后置++
                           *                   间接访问操作符(解引用操作符)
                       (类型)               强制类型转换
注:2+3,+则为双目操作符,即有两个操作数,  单目操作符:只有一个操作数

        

(6) 关系操作符:   >
                              >=
                              <
                              <=
                              !=              用于测试“不相等”
                              ==             用于测试“相等”

        

(7) 逻辑操作符:   &&             逻辑与
                               ||               逻辑或 

        

(8) 条件操作符(三目操作符):exp1   ?   exp2  :  exp3
                                                 真           执行     不执行
                                                 假          不执行    执行         

               

(9) 逗号表达式:exp1, exp2, exp3, …expN

        

(10) 下标引用、函数调用和结构成员: [](下标引用操作符)   ()(函数调用操作符)   .    ->

        在之前的文章中我们讲解了 算术操作符 和 逻辑操作符,那么今天我就将其余的操作符给大家重点讲解一下吧。由于操作符的类型较多,小编将以两篇文章的形式为大家讲解完这些操作符。

2. 移位操作符

        因为移位操作符涉及二进制位的相关知识,下面就先给大家讲解一下移位操作符的知识拓展吧!

2.1 移位操作符知识拓展 —— 原码、反码、补码

        在计算机内存中对数据的存储不是直接存储的,而是将数据转化为二进制后再存储的。下面我就带大家了解一下整数的二进制

        整数的二进制表现形式有三种:原码、反码、补码。而这三种表现形式有如下几个特点需要牢记:

                1. 正整数的原码、反码、补码是相同的;负整数的原码、反码、补码是要计算的

                2. 不管是正整数还是负整数都可以写出二进制原码,根据正负直接写出的二进制序列就是原码。

                3. 一个整型是4个字节 = 32 bit位;最高位是符号位,符号位是1表示负数,符号位是0表示正数。举例如下:

int a = 15;

那么a的原码就是:

0 000 0000 0000 0000 0000 0000 0000 1111
 

int b = -15;

那么b的原码就是:
1 000 0000 0000 0000 0000 0000 0000 1111

                4. 整数在内存中存储的是补码而并不是原码,计算的时候也是使用补码计算的。

                5. 由于正整数的原码、反码、补码是相同的,而负整数的原码、反码、补码是要计算得知的,那下面我就为大家讲解如何通过负整数的原码 求得 反码和补码。

同样以负整数 -15 为例
int b = -15;   最高位是符号位,而负整数的符号位为1
故原码为:
1000 0000 0000 0000 0000 0000 0000 1111 - 原码


反码的计算 —— 原码的符号位不变,其他位 按位取反 (按位取反通俗点讲就是 该位为0则变成1,该位为1则变成0),故 -15 的反码为:
1111 1111 1111 1111 1111 1111 1111 0000 - 反码


补码的计算 —— 将反码加一就是补码
1111 1111 1111 1111 1111 1111 1111 0001 - 补码

2.2 移位操作符讲解

        移位操作符有两种:>>(右移), << (左移)。

        需要注意的是:移位操作符的操作数只能是整数,同时移位移动的是补码的二进制序列(而非原码),因此在移动后需要通过补码来反向计算出原码,从而得出整数数值为多少。

2.2.1 右移操作符 ( >> )

右移操作符移位的规则有两种:算术右移逻辑右移

        1. 算术右移 —— 右边丢弃,左边补原来的符号位。
        2. 逻辑右移 —— 右边丢弃,左边直接补0。

        在C语言中并没有明确规定到底是算术右移还是逻辑右移,一般编译器上采用的是 算术右移。
        我将在VS编译器上为大家测试 VS上采用的是算术右移 还是 逻辑右移?

同样以 -15 为例,上面计算出了 -15的补码为:
1111 1111 1111 1111 1111 1111 1111 0001 - 补码


(1)假设为 算术右移:
那么右移1位后的补码为:
1111 1111 1111 1111 1111 1111 1111 1000  -  补码


那其反码为:(补码减1即为反码)
1111 1111 1111 1111 1111 1111 1111 0111  -  反码


而其原码为:(对反码进行按位取反则为原码,注意符号位不变)
1000 0000 0000 0000 0000 000 0000 1000  -  原码
则如果是算术右移,那么 -15 在右移1位后的结果为 -8


(2)假设为 逻辑右移:
那么右移1位后的补码为:
0111 1111 1111 1111 1111 1111 1111 1000  -  补码


那其反码为:(补码减1即为反码)
0111 1111 1111 1111 1111 1111 1111 0111  -  反码


而其原码为:(对反码进行按位取反则为原码,注意符号位不变)
0000 0000 0000 0000 0000 000 0000 1000  -  原码
则如果是逻辑右移,那么 -15 在右移1位后的结果为 8

        显然VS编译器上采用的是算术右移,当然大家感兴趣的话可以自己手动计算 15 右移1位后的结果是多少呀!

        这里告诉大家一个右移计算的小技巧:在正整数中,右移k位相当于除以2的k次方(向下取整),左移k位相当于乘以2的k次方。

2.2.2 左移操作符 ( << )

左移操作符的移位规则只有一种:左边丢弃,右边补0。

这里以正整数 6 为例:


6 的补码为:
0000 0000 0000 0000 0000 0000 0000 0110 —— 补码


左移之后,6 的补码为:
0000 0000 0000 0000 0000 0000 0000 1100 —— 补码


而由于6是正整数,正整数的原码与补码相同,故原码为:
0000 0000 0000 0000 0000 0000 0000 1100 —— 原码


所以 6 在左移1位后的结果位:12

        这里需要注意的是:对于移位运算符,不要移动负数位,这个是标准未定义的(warning C4293: “>>”: Shift 计数为负或过大,其行为未定义)。

3. 位操作符

位操作符有三种:& (按位与)           | (按位或)            ^ (按位异或)

        位操作符有如下几点需要牢记:

                1. 位操作符操作的也是二进制位,并且也是对补码进行操作。

                2. 位操作符的 操作数必须是整数。

3.1 & (按位与)

        那何为 按位与 呢?简单来说,按位 则是对每一位二进制位进行操作,与 则有并且的意思。因此按位与的操作规则为:对应二进制位有0则为0,两个同时为1才为1。

以正整数 a = 3,负整数 b = -5 为例。


a = 3 的补码为:
0000 0000 0000 0000 0000 0000 0000 0011 —— 补码
b = -5 的原码和补码如下:
1000 0000 0000 0000 0000 0000 0000 0101 —— 原码
1111 1111 1111 1111 1111 1111 1111 1011 —— 补码


将 a和b进行按位与:int c = a & b;
0000 0000 0000 0000 0000 0000 0000 0011
1111  1111  1111 1111  1111  1111  1111  1011
& -- 对应二进制位有0则为0,两个同时位1才为1
0000 0000 0000 0000 0000 0000 0000 0011 —— 按位与后的补码


因此按位与后的原码为,即c的原码为:
0000 0000 0000 0000 0000 0000 0000 0011
故c 为 3,即 a & b = 3

3.2 | (按位或)

        按位或:也是对每一位二进制位进行操作,而 或 即有 或者 的意思。故按位或的操作规则为:对应二进制位有1则为1,两个同时为0才为0。

同样以正整数 a = 3,负整数 b = -5 为例。


a = 3 的补码为:
0000 0000 0000 0000 0000 0000 0000 0011 —— 补码
b = -5 的补码如下:
1111 1111 1111 1111 1111 1111 1111 1011 —— 补码


将 a和b进行按位或:int c = a | b;
0000 0000 0000 0000 0000 0000 0000 0011
1111  1111  1111 1111  1111  1111  1111  1011
| —— 对应二进制位有1则为1,两个同时为0才为0
1111 1111 1111 1111 1111 1111 1111 1011 —— 按位或后的补码


因此 按位或 后的原码为,即c的原码为:
1000 0000 0000 0000 0000 0000 0000 0101
故c 为 -5,即 a | b = -5

3.3 ^ (按位异或)

        按位异或的操作规则为:对应的二进制位相同为0,相异为1。

以正整数 a = 3,负整数 b = -5 为例。


a = 3 的补码为:
0000 0000 0000 0000 0000 0000 0000 0011 —— 补码
b = -5 的补码如下:
1111 1111 1111 1111 1111 1111 1111 1011 —— 补码


将 a和b进行 按位异或:int c = a ^ b;
0000 0000 0000 0000 0000 0000 0000 0011
1111  1111  1111 1111  1111  1111  1111  1011
^ —— 对应的二进制位相同为0,相异为1
1111 1111 1111 1111 1111 1111 1111 1000 —— 按位异或后的补码


因此 按位异或 后的原码为,即c的原码为:
1000 0000 0000 0000 0000 0000 0000 1000
故c 为 -8,即 a ^ b = -8

3.4 按位异或的小技巧和测试题

        下面为大家讲解一下按位异或的几个小技巧:

                1. 异或是支持交换律的,异或是没有先后顺序的。 即:a ^ b ^ c = a ^ c ^ b = c ^ b ^ a

                2. 对于一个整数a,a ^ a = 0;    a ^ 0 = a

        对于以上两个小技巧,我们就可以做一个测试题:不能创建临时变量(第三个变量),实现两个整数的交换。(代码如下)

#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;
}

那为什么这样就能实现交换呢?


最重要的肯定就是下面这三步了:
(1)   a = a ^ b;
(2)   b = a ^ b; 
(3)   a = a ^ b;


由于先有(1),那么(2)实际为: b = a ^ b = (a ^ b) ^ b = a ^ b ^ b = a;  即将a赋值给了b


则(3) 实际为:a = a ^ b = (a ^ b) ^ a = a ^ b ^ a = a ^ a ^ b = b;  即将b赋值给了a


从而实现了整数 a 和 b的交换。

4. 赋值操作符

        赋值操作符比较好理解,其实就是将 赋值符 和 等号(=) 结合起来,其目的可能是为了让代码看起来更简洁。

        赋值操作符主要有这几种:+=        -=       *=       /=      %=       >>=       <<=       &=       |=       ^=

以 += 操作符为例:


int a = 12;
(1)  a += 1;
(2)  a = a + 1;


(1) 和 (2) 的结果是一样的,最后结果都为 13,但 (1) 的代码看起来的更简洁。

        其余 赋值操作符 也是一样的效果,感兴趣的小伙伴们可以自己尝试一下呀!

5. 单目操作符

        单目操作符,简单来说,就是只有一个操作数。而单目有这些:!        -        +        &        sizeof        ~        --        ++        *        (类型)

5.1 ! (逻辑反操作)

        举个例子:如果 flag 的值为真,则 !flag 则表示为假。因此 ! 操作符多用于判断语句 和 循环语句中。

5.2 - (负值) 和 + (正值)

        正值 和 负值和我们平常在数学上的理解是一样的,这里就不再赘述了。

5.3 & (取地址操作符) 和 * (间接访问操作符)

        & (取地址操作符) 和 * (间接访问操作符) 多用于指针

对于 & 操作符


假设此时有整数:int a = 18;
我们如果想取出数据 a 的地址,并将该地址赋值给指针pa,此时就需要用到 & 。如下:
int* pa = &a;


而如果此时想要对 a 的数据进行修改,有以下两种方式:
(1)  a = 20;
(2)  *pa = 20;


对于(2),因为pa已经存放了a的地址,所以通过pa中存放的地址,找到指向的空间(内容)并进行修改。
因此 * 又称为 解引用操作符。

5.4 sizeof 操作符

        sizeof 操作符的作用是:求出操作数的类型长度,并以字节为单位。举例如下:

由于变量a是整型类型,因此 sizeof(a) 自然也为4。

而最后一句代码:printf("%zd\n", sizeof a);  说明sizeof只是一个操作符,而并不是函数。因为如果为函数,则必须为 sizeof(a) 而不能是 sizeof a

5.5 ~ (按位取反)

        在上述讲解移位操作符时,给大家讲解了一下什么是按位取反。如果大家不了解可以往上看哦!而 ~ 操作符的规则就是:对这个操作数的二进制位进行按位取反。

但这里有一点不同的是:~是将该操作数的所有二进制位进行按位取反,包括符号位!!!

以int a = 0 为例:
a 的补码为:
0000 0000 0000 0000 0000 0000 0000 0000 


对a 进行 按位取反: int b = ~a
1111 1111 1111 1111 1111 1111 1111 1111 —— b的补码


故b的原码为:
1000 0000 0000 0000 0000 0000 0000 0001
因此 b = -1

5.6 -- 和 ++

        -- 和 ++ 就是将数据进行 减1 和 加1 的操作。而++ 和 -- 又分为 前置、后置++ 和 前置、后置--

        因为两种操作符功能类似,这里我们以 ++操作符 为例进行讲解:

前置++:即操作符在前,操作数在后。
后置++:即操作数在前,操作符在后。
操作符位置的不同,所带来的效果也不一样。


(1) 对于前置++:
int a = 3;
int b = ++a;
那么a 的结果为4,b的结果也为4。这是因为对于前置++来讲,++操作符会先将 a 进行 加1 操作,然后再将 加1后的a 赋值给b。


(2) 对于后置++:
int a = 3;
int b = a++;
那么a 的结果为4,b的结果为3。这是因为对于后置++来讲,++操作符会先将 a 的值赋值给b,再对自身进行 加1 操作。

5.7 (类型)

        (类型) 是指 强制类型转换。那很多小伙伴好奇这有什么用呢?假设我们要在不同的数据类型之间进行赋值 或 比较等操作,如果直接进行赋值,则编译器会报警告。(例如直接将浮点型的数据 赋值 给整型的数据)

        因此此时要将浮点型的变量a 强制类型转换为 整型,这样编译器才不会发出警告。

        今天就先分享到这里啦,剩下的 操作符 我将会在下一篇文章为大家一一进行讲解哦!!我们下一篇文章再见啦!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gm/ID设计方法学习笔记(一)

前言&#xff1a;为什么需要gm/id &#xff08;一&#xff09;主流设计方法往往侧重于强反型区&#xff08;过驱>0.2V&#xff09;&#xff0c;低功耗设计则侧重于弱反型区&#xff08;<0&#xff09;&#xff0c;但现在缺乏对中反型区的简单和准确的手算模型。 1.对于…

10月2日笔记(内网资源探测篇)

内网资源探测 在内网渗透中&#xff0c;测试人员往往需要通过各种内网扫描技术来探测内网资源的情况&#xff0c;为后续的横向渗透做准备&#xff0c;通常需要发现内网存活的主机&#xff0c;并探测主机的操作系统、主机开放了哪些端口、端口上运行了哪些服务、服务的当前版本…

SQL SERVER 从嫌弃存储到爱上存储过程我给存储过程开发了版本控制工具和远程调试功能...

优缺点 SQL SERVER 爱上存储过程我给存储过程开发了版本控制工具和远程调试功能 先说说 存储过程的优缺点吧存储过程的优点 提高执行效率&#xff1a;存储过程是预编译的&#xff0c;执行速度较快&#xff0c;减少了网络传输量。 减少开发工作量&#xff1a;存储过程可以将复杂…

数据结构——对顺序线性表的操作

大家好啊&#xff0c;今天给大家分享一下对于顺序线性表的相关操作&#xff0c;跟随我的步伐来开始这一篇的学习吧&#xff01; 如果有知识性错误&#xff0c;欢迎各位指正&#xff01;&#xff01;一起加油&#xff01;&#xff01; 创作不易&#xff0c;希望大家多多支持哦…

中级软件设计师:一文搞懂下午第一题——数据流图技术

中级软件设计师&#xff1a;一文搞懂下午第一题——数据流图技术 0. 答题技巧-【11-12分】分必拿方法0. 本章的考点1. 数据流图的基本元素1.1 数据流1.2 加工1.3 数据存储(文件)1.4 外部实体1.5 分层数据流图&#xff08;DFD&#xff09;1.6 自顶至下&#xff0c;逐步精化1.6.1…

8645 归并排序(非递归算法)

### 思路 非递归归并排序通过逐步合并相邻的子数组来实现排序。每次合并后输出当前排序结果。 ### 伪代码 1. 读取输入的待排序关键字个数n。 2. 读取n个待排序关键字并存储在数组中。 3. 对数组进行非递归归并排序&#xff1a; - 初始化子数组的大小curr_size为1。 - 逐…

GO网络编程(二):客户端与服务端通信【重要】

本节是新知识&#xff0c;偏应用&#xff0c;需要反复练习才能掌握。 目录 1.C/S通信示意图2.服务端通信3.客户端通信4.通信测试5.进阶练习&#xff1a;客户端之间通信 1.C/S通信示意图 客户端与服务端通信的模式也称作C/S模式&#xff0c;流程图如下 其中P是协程调度器。可…

使用VBA快速生成Excel工作表非连续列图片快照

Excel中示例数据如下图所示。 现在需要拷贝A2:A15,D2:D15,J2:J15,L2:L15,R2:R15为图片&#xff0c;然后粘贴到A18单元格&#xff0c;如下图所示。 大家都知道VBA中Range对象有CopyPicture方法可以拷贝为图片&#xff0c;但是如果Range对象为非连续区域&#xff0c;那么将产生10…

Web安全 - 安全防御工具和体系构建

文章目录 安全标准和框架1. 国内安全标准&#xff1a;等级保护制度&#xff08;等保&#xff09;2. 国际安全标准&#xff1a;ISO27000系列3. NIST安全框架&#xff1a;IDPRR方法4. COBIT与ITIL框架 防火墙防火墙的基本作用防火墙的三种主要类型防火墙的防护能力防火墙的盲区 W…

【MATLAB2024b】安装离线帮助文档(windows)

文章目录 一、在 MATLAB 设置中安装二、从math works 网站下载ISO&#xff1a;给无法联网的电脑安装三、重要说明 版本&#xff1a;matlab 2024b&#xff08;或者大于等于2023a&#xff09; 所需空间&#xff1a;10~15 GB 平台&#xff1a;Windows 需要注册math works账号。 一…

【计算机网络】详解UDP协议格式特点缓冲区

一、UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度&#xff1b;如果16位UDP检验和出错&#xff0c;报文会被直接丢弃。 1.1、检验和出错的几种常见情况 数据传输过程中的比特翻转&#xff1a;在数据传输过程中&#xff0c;由于物理介质或网络设…

UE5.4.3 录屏回放系统ReplaySystem蓝图版

这是ReplaySystem的蓝图使用方法版&#xff0c;以第三人称模版为例&#xff0c;需要几个必须步骤 项目config内DefaultEngine.ini的最后添加&#xff1a; [/Script/Engine.GameEngine] NetDriverDefinitions(DefName"DemoNetDriver",DriverClassName"/Script/…

二、Spring Boot集成Spring Security之实现原理

Spring Boot集成Spring Security之实现原理 一、Spring Security实现原理概要介绍二、使用WebSecurityConfiguration向Spring容器中注册FilterChainProxy类型的对象springSecurityFilterChain1、未配置securityFilterChain过滤器链时使用默认配置用于生成默认securityFilterCha…

JDBC 快速入门

JDBC 快速入门 搭建步骤代码实现数据库java 代码 搭建步骤 准备数据库官网下载数据库连接驱动jar 包。https://downloads.mysql.com/archives/c-j/创建 java 项目&#xff0c;在项目下创建 lib 文件夹&#xff0c;将下载的驱动 jar 包复制到文件夹里选中 lib 文件夹右键 ->…

第二十一章 (动态内存管理)

1. 为什么要有动态内存分配 2. malloc和free 3. calloc和realloc 4. 常⻅的动态内存的错误 5. 动态内存经典笔试题分析 6. 总结C/C中程序内存区域划分 1.为什么要有动态内存管理 我们目前已经掌握的内存开辟方式有 int main() {int num 0; //开辟4个字节int arr[10] …

【EXCEL数据处理】000009 案列 EXCEL单元格数字格式。文本型数字格式和常规型数字格式的区别

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000009 案列 EXCEL单元格数字格式。文本型数字格式和…

CTK框架(十一):使用的常见问题

目录 1.MF文件路径 2.服务必须要接口类 3.插件名命名要求 4.生命周期问题 5.一个接口对多个实现注意 6.中文输出注意 7.同一插件安装注意 8.添加元数据 9.关于升级插件时遇到的问题 10.不同插件定义资源文件注意路径问题 11.安装插件 12.插件依赖 1.MF文件路径 在…

K8S:开源容器编排平台,助力高效稳定的容器化应用管理

云计算de小白 Kubernetes&#xff08;简称K8s&#xff09;是一个开源容器编排平台&#xff0c;用于自动化部署、扩展和管理容器化应用程序。 K8S诞生于Google&#xff0c;基于其多年在生产环境运行容器的经验&#xff0c;目前已成为现代微服务架构和云原生应用的核心技术。 图…

【C++算法】10.滑动窗口_长度最小的子数组

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 209. 长度最小的子数组 题目描述&#xff1a; 解法 解法一&#xff1a;暴力求解&#xff08;会超时&#xff09; 暴力枚举出所有子数组的和。 查找子数组n2&#xff0…

云计算 Cloud Computing

文章目录 1、云计算2、背景3、云计算的特点4、云计算的类型&#xff1a;按提供的服务划分5、云计算的类型&#xff1a;按部署的形式划分 1、云计算 定义&#xff1a; 云计算是一种按使用量付费的模式&#xff0c;这种模式提供可用的、便捷的、按需的网络访问&#xff0c;进入可…