C语言操作符详解

目录

  • 前言
  • 一.深度理解取余/取模运算
  • 二.续行符与转义字符
  • 三.逻辑运算符
  • 四.位操作符
    • 1. 按位与 按位或 按位取反
    • 2.移位操作符
    • 实战(重点)
  • 五.深入理解 a++
  • 六.操作符优先级

前言

所有关于运算的操作符,不管是逻辑运算还是位运算,都是先将变量在内存中提取在CPU内存寄存器中进行运算,然后计算的结果在写回内存,所以我们操作的都是补码,因为内存中存储的都是数据的补码,只有我们打印某个数据时才会涉及到原码的概念。
建议在学习运算操作符之前先明白数据(整形)在内存中如何存储

《数据到底在内存中如何存储》

一.深度理解取余/取模运算

C语言操作符详解_第1张图片
对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。

想要得到小数部分一定一个操作数得是浮点数C语言操作符详解_第2张图片

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

C语言操作符详解_第3张图片
C语言操作符详解_第4张图片

1.第一个问题整数的除法是如何取整的

C语言操作符详解_第5张图片
C语言操作符详解_第6张图片
为什么是这样的一种取整方式呢。
C语言操作符详解_第7张图片
其实C语言中的默认取整方式是向零取整

向零取整的函数
C语言操作符详解_第8张图片
C语言操作符详解_第9张图片
向负无穷方向取整的函数,返回不大于x的最大整数值
C语言操作符详解_第10张图片

C语言操作符详解_第11张图片
C语言操作符详解_第12张图片
向正无穷方向取整的函数,返回不小x的最小整数值
C语言操作符详解_第13张图片
C语言操作符详解_第14张图片
C语言操作符详解_第15张图片
四舍五入取整
C语言操作符详解_第16张图片
C语言操作符详解_第17张图片
取整方案对比:
C语言操作符详解_第18张图片
C语言操作符详解_第19张图片
这里你会发现就算不同的取整方式可能会得到同样的值。

重点来了:取模和取余一样嘛

先说结论

本质 1 取整:
取余:尽可能让商,向零取整
取模:尽可能让商,向-∞方向取整

而我们前面已经说了C语言默认的取整方案为向零取整,所以C语言中的%运用其实是在取余数

被除数、除数、商、余数的关系:

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 且0 ≤ |r|< |d|。。其中,q被称为商,r 被称为余数。

C语言操作符详解_第20张图片
接下来来一个怪一点的:-10%3=?

在VS2013编译器中:
C语言操作符详解_第21张图片

在Python 2.7.12
C语言操作符详解_第22张图片
为什么会出现不同的结果呢

根本原因是
C语言中 % 是取余数 — 得出的商向零取 整
Python中% 是取模 — 得出的商向负无穷取整

这样我们就能解释了,我们知道了商知道被除数和除数就可以求出余数

C语言操作符详解_第23张图片
r余数的大小是取决于商的,而商的大小有取决与取整方式:

对任何一个大于0的数,对其进行0向取整和-∞取整,取整方向是一致的。故取模等价于取余

对任何一个小于0的数,对其进行0向取整和-∞取整,取整方向是相反的。故取模不等价于取余

这句是为什么C语言中通常将取余等价与取模,原因就是我们通常都是正数,而正数的取余才真正等价于取模。

同符号数据相除,得到的商,一定是正数(正数vs正整数),即大于0!=在对其商进行取整的时候,不管是向零取整还是向负无穷取整取整的方向都是一样的所以所得的商也一样,余数也一样,所以取模等价于取余

同符号时:取模等价于取余
C语言操作符详解_第24张图片
不同符号时所得的商一定是负数,取模向负无穷取整,取余是向零取整则取整方向不一样,所以所得的商不一样,所得的余数也不一样。

C语言操作符详解_第25张图片

二.续行符与转义字符

C语言操作符详解_第26张图片注意:续航符的后面不能带任何东西(包括空格)
C语言操作符详解_第27张图片

  • \的转义功能:
    C语言操作符详解_第28张图片
    C语言操作符详解_第29张图片
    C语言操作符详解_第30张图片
    一道面试题:
    C语言操作符详解_第31张图片
    解析:
    C语言操作符详解_第32张图片
    在这里插入图片描述

C语言操作符详解_第33张图片
C语言操作符详解_第34张图片

\0 与 数值0,NULL,和字符零’0’的区别
在这里插入图片描述
在这里插入图片描述
*NULL的数值其实是零,只不过NULL的类型是 void 类型

C语言操作符详解_第35张图片
\0的ACSLL值也就是十进制表示也为0, 只不过\0的类型为字符型。

C语言操作符详解_第36张图片
而 '0’字符零是ACSLL值为48 .

总结:\0 与 数值0,NULL数值相同都为0类型不同,

  • 回车与换行
    在这里插入图片描述
    回车与换行本质是两个概念:
    回车:光标回到当前行的最开始
    换行:光标移动到下一行

只不过 \n 既回车又换行。

利用回车做一个小程序:旋转光标:
C语言操作符详解_第37张图片
因为我们添加了 \r,所以每次打印都回到当前行的最开始覆盖上一次的打印

利用回车做一个小程序:倒计时:
C语言操作符详解_第38张图片
因为我们添加了 \r,所以每次打印都回到当前行的最开始覆盖上一次的打印

三.逻辑运算符

&& 逻辑与
|| 逻辑或

逻辑与的特点:
1.所有表达式都成立才成立
2.从左向右结合
3.若有一个表达式不成立则后面的表达式不执行

所有表达式成立才成立:
C语言操作符详解_第39张图片
若有一个表达式不成立则后面的表达式不执行:
C语言操作符详解_第40张图片
注意:
这里成立与不成立的感念是真假的概念:非0为真,0为假

逻辑或的特点:
1.所有表达式有一个成立则成立
2.从左向右结合
3.若有一个表达式成立则后面的表达式不执行

C语言操作符详解_第41张图片
都不成立才不成立:所有表达式全部执行一遍
C语言操作符详解_第42张图片

笔试题:
C语言操作符详解_第43张图片

解析:
C语言操作符详解_第44张图片
变式1:
C语言操作符详解_第45张图片
解析:
C语言操作符详解_第46张图片

四.位操作符

1. 按位与 按位或 按位取反

所谓双目运算符:有两个操作数,操作数必须是整数

所有的运算都是要经过CPU来执行的,执行的过程中要想内存中提取数据,而存储在内存中的数据全是补码,所以我们的运算全是针对与数据的补码

按位与运算 &
按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应二进制位相与。只有对应的两个二进制位均为1时,结果位才为1 ,否则为0。

C语言操作符详解_第47张图片

按位或运算 |
按位或运算符“|”是双目运算符。 其功能是参与运算的两数各对应的二进制位相或。只要对应的二个二进制位有一个为1时,结果位就为1。

C语言操作符详解_第48张图片
求反运算~
求反运算符~为单目运算符,具有右结合性。 其功能是对参与运算的数的各二进位按位求反。

C语言操作符详解_第49张图片
注意:符号位照样取反

按位异或运算 ^
按位异或运算符“^”是双目运算符。 其功能是参与运算的两数各对应的二进制位相异或,当两对应的二进制位相异时结果为1,相同结果为0,

C语言操作符详解_第50张图片

按为异或的特点:
最好能记住解题块的很
性质:
1.交换律 a^ b = b^a
2.结合律 a^ b ^ c = a^ (b^c)
3.任何数后零异或都是它本身
4. 自身与自身异或为0

其实上面的特点很好证明只要记住:相同为0,相异为1

实战:交换两个数

1.创建临时变量
C语言操作符详解_第51张图片
2. 不创建临时变量
C语言操作符详解_第52张图片
缺陷:当两个数的足够大时相加可能会溢出
3. 异或
C语言操作符详解_第53张图片
C语言操作符详解_第54张图片
C语言操作符详解_第55张图片
其实知道异或的特性很快能做出来

2.移位操作符

左移: 最高位丢弃,最低位补零
右移:
1.无符号数:最低位丢弃,最高位补零[逻辑右移]
2.有符号数:最低位丢弃,最高位补符号位[算术右移]

注意:
有无 符号看的是数据的类型,与内存中保存的数据无关

左移: 最高位丢弃,最低位补零
C语言操作符详解_第56张图片
右移:
1.无符号数:最低位丢弃,最高位补零[逻辑右移]

C语言操作符详解_第57张图片
2.有符号数:最低位丢弃,最高位补符号位[算术右移]
C语言操作符详解_第58张图片

如何理解丢弃:
左移或者右移都是计算,都要在CPU中进行,可是参与移动的变量,是在内存中的。所以需要先把数据移动到CPU内寄存器中,在进行移动,实际移动的过程中,是在寄存器中进行的,即大小固定的单位内。那么,左移右移一定会有位置跑到"外边"的情况

所以还有一个结论:
我们左移右移都是针对内存中的数据而言的,而内存中的存储的数据的补码

到底什么时候需要原码:只有我们在打印某个数据时,从内存中拿出来的时候。

实战(重点)

设置数据的指定比特位为1,其他比特位不变
在这里插入图片描述
C语言操作符详解_第59张图片

设置数据的指定比特位为0,其他比特位不变
在这里插入图片描述
C语言操作符详解_第60张图片

显示数据的所有比特位,并记比特位中有多少个1

void ShowBits(int n)
{
	int count = 0;
	int num = sizeof(n) * 8 - 1;
	while (num>=0)
	{
		if (n&(1<<num))
		{
			printf("%d ",1);
			count++;
		}
		else
		{
			printf("%d ", 0);
		}
		num--;
	}
	printf("\n");
	printf("1的个数:%d\n", count);
}

C语言操作符详解_第61张图片

实验效果:
C语言操作符详解_第62张图片
C语言操作符详解_第63张图片
左移:一般情况下左移一位就乘以2

	//左移
	unsigned int a = 10;
	printf("%u\n", a << 1);
	printf("%u\n", a << 2);
	printf("%u\n", a << 3);
	return 0;

C语言操作符详解_第64张图片
右移:一般情况下右移一位就除以2
C语言操作符详解_第65张图片
这个我就不分析了, 与左移类似。

特殊情况:-1右移还是-1因为最高位补的是符号位
C语言操作符详解_第66张图片

重点理解右移:
注意:
有无 符号看的是数据的类型,与内存中保存的数据无关

C语言操作符详解_第67张图片
C语言操作符详解_第68张图片
如果对整形如何存储在内存中,或者对无符号类型的变量为什么能存储负数有疑问请看——<数据到底在内存中如何存储>

移位一个要注意的点:
+号的优先级比 移位操作符要高
C语言操作符详解_第69张图片
C语言操作符详解_第70张图片
有先级的概念一定要注意:拿捏不准就加上括号,准没错

五.深入理解 a++

a++ 在任何情况下都是先使用后++嘛

答案是否定的:

当有a++被使用时:
确实是先使用然后在完成自增

C语言操作符详解_第71张图片

当有a++没有被使用时:
a直接自增

C语言操作符详解_第72张图片
接下来看一段复杂代码:
C语言操作符详解_第73张图片

在VS2013编译器中:
C语言操作符详解_第74张图片
在linux下gcc编译器中:
C语言操作符详解_第75张图片
为什么同一份代码在不同的编译器下,结果不同呢
vs2013 -->12
gcc —>10

根本原因写出这种代码:计算的途径有很多种

  • vs2013 -->12

C语言操作符详解_第76张图片
根本原因是编译器先将i自增3次在指向i的相加
怎么计算方式并没有违反操作符的优先级与结合性的规则

优先级:只会影响到两个相邻的操作符先执行哪个

  • gcc —>10

C语言操作符详解_第77张图片
相当于先执行前面i++ ,让i自增两次i变成3,然后在执行前面两个i相加 得3+3得6,最后让最后一个i++,i变成4,最后相加的3+3+4=10

看完了汇编是不是还是有点没理解:
其实这个式子与我们日常数学中的一个式子差不多:

在这里插入图片描述

  • 贪心法

C语言有这样一个规则:每一个符号应该包含尽可能多的字符。也就是说,编译器将程序分解成符号的方法是,从左到右一个一个字符的读人,如果该字符可能组成一个符号,那么再读人下一个字符时,判断已经读人的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读人的字符组成的字符串已不再可能组成一个有意义的符号。这个处理的策略被称为“贪心法”。需要注意的是,除了字符串与字符常量,符号的中间不能嵌有空白(空格、制表符、换行符等),比如:== 是单个符号,而= =是两个等号。

C语言操作符详解_第78张图片
C语言操作符详解_第79张图片
贪心法简单点说就是:尽可能多的匹配符号,组成C语言中多字符符号,例如:++ – &= <<= … 所以写这些符号中间不要添加空格

看一个例子就明白了:

在这里插入图片描述

C语言操作符详解_第80张图片

六.操作符优先级

复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
L-R :从左向右
R-L :从右向左
3. 是否控制求值顺序。

逻辑或 || 逻辑与 && 条件操作符 ? : 逗号表达式

两个相邻的操作符先执行哪个取决于他们的优先级如果两者的优先级相同,取决于他们的结合性。

操作符优先级,越上面优先级越高
C语言操作符详解_第81张图片
条件操作符:
格式:
如果表达式1为真,则执行表达式2,表达式2是整个表达式的结果
如果表达式1不成立,则执行表达式3,表达式3是整个表达式的结果

C语言操作符详解_第82张图片

举例:求两个数的较大值
C语言操作符详解_第83张图片
其实也可以实现嵌套,在某个表达式又搞一个 exp1? exp2:exp3

  • 逗号表达式
    逗号表达式,就是用逗号隔开的多个表达式。
    逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

C语言操作符详解_第84张图片

你可能感兴趣的:(c语言,开发语言)