小边同学强势总结之C语言操作符
Posted 小边同学:)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小边同学强势总结之C语言操作符相关的知识,希望对你有一定的参考价值。
目录一览
引:
操作符这部分内容呐,在小边眼里,是看似食之无味,弃之又非常非常可惜的一部分,而且其实是蛮有意思的。
这么讲是因为我个人认为,学校老师把它打散散布在零星各处又不够深入,而如果出题又可能“刁钻”,所以今天拿出来好好总结一下。
正文开始@边通书
一、操作符分类
二、算术操作符
+,-,* 都非常简单,唯一要注意的两点就是 乘 * 和 取模 %
除号 /
运行结果:
取模 %(整除之后求余数)
三、移位操作符
移位操作符移动的都是 内存中的 二进制位。
其实对于整数的二进制位有3种表示方法:原码,反码,补码,整数在内存中存储的都是补码。
呀,怕小伙伴忘记先说一下,最高位也就是符号位,正数为0,负数为1奥。
左移操作符<<(相对简单)
1.左移原理剖析
1.左移正数a:
运行结果:
2.左移负数c:
运行结果
2.右移原理剖析
右移操作符>> (其实也没夺复杂啦)
(1)右移正数a:
运行结果:
(2)右移负数a:
运行结果:
可见,vs2013采用的是算术右移(即补符号位),或者说大多数编译器都采用算术右移。
且,算术右移似乎更合适一些,你是负数,右移之后仍为负数。
3.注:
可爱同学写的胡乱代码,如下
四、位操作符
1.原理剖析
按位与&
按位或|
按位异或^
2.典例
那么这些位操作符到底有什么用呢?下面看:
典例1:计算某整数存储在内存二进制位中有多少1?
1.方法一:
代码:
#include<stdio.h>
int main()
{
int a = 15;
int count = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if (((a >> i) & 1) == 1)
{
count++;
}
}
printf("%d\\n", count);
return 0;
}
运行结果,如我所愿:
3.变态面试题
一道变态的面试题:不创建临时变量(第三个变量),实现两个数交换。
我们最最简单也是最常用的办法:
方法一:加减法
运行结果:
此方法虽满足不创建临时变量的要求,但是有一定问题的:
如果a,b都很大且还在int范围之内,buta = a + b
很有可能溢出。依然不是最好的解决方案。
方法二:异或的方法
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a^b;
b = a^b;
a = a^b;
printf("a = %d,b = %d\\n", a, b);
return 0;
}
运行结果:
原理剖析:
异或这个操作符是很有意思的,它让我想起了集合论与图论里的对称差,那个小三角符号。
然而这种方法实际用的比较少:原因:
1.代码可读性不好,乍一看都不知道什么意思
2.只适用于整形
3.且执行效率低
优点是满足了面试官的需求哈哈哈哈。
五、赋值操作符
赋值操作符是一个很棒的操作符,可以让你得到一个之前不满意的值。
1.连续赋值
2.复合赋值符
a += 2;
即为a = a + 2;
a >>= 1;
即为a = a>>1;
a &= 1
即为a = a & 1
,
显然前者更加简洁。
类似的有这些:
+= ,-=,*=, /=,%=,<<=,>>=,&=,|=,^=
六、单目操作符
单目操作符:即为只有一个操作数的操作符
逻辑反!
一般使用场景如下:
正号+ 负号-
比较简单,不多讲
取地址& 解引用*
sizeof
1.作用剖析 与 strlen()简单对比
运行结果:
2.sizeof是操作符,不是函数
面试官问你:“小伙子,sizeof是不是函数?”,你说,“是!”,面试官“孩子,回家吧。”哈哈哈哈哈
下面用代码简要说明一下:
3.sizeof 内部的表达式是不参与真实运算的
看看以下代码,小伙伴们觉得结果是什么?
#include<stdio.h>
int main()
{
int a = 5;
short s = 10;
printf("%d\\n", sizeof(s = a + 2));//?
printf("%d\\n", s);//?
return 0;
}
运行结果:
原理剖析:
4.sizeof与数组
读以下代码,给出你的结果:
#include <stdio.h>
void test1(int arr[])
{
printf("%d\\n", sizeof(arr));//(3)
}
void test2(char ch[])
{
printf("%d\\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\\n", sizeof(arr));//(1)
printf("%d\\n", sizeof(ch));//(2)
test1(arr);
test2(ch);
return 0;
}
原理剖析:
运行结果:
32位平台:
按位取反~
二进制位全部取反,连符号位也要取反!!!
1.上代码感受一下
运行结果:
调试窗口,看看内存中~a的真实存在:
2.应用场景
++,- -
1.前置++
运行结果:
2.后置++
运行结果:
前置- -,后置- -,都同理,不赘述。
3.不建议研究过于复杂的相关代码
在vs下,运行结果为12;
然而在Linux平台下,gcc编译器算出结果为10,
那么这段代码本身就是错误的,就没有什么必要纠结,也不要写这样的代码。
至于为什么出现这种情况,后文会讲。
强制类型转换(类型)
七、关系操作符
两 同类型 的变量之间 比较大小,比较简单,不做赘述
<,>,<=,>=,==,!=
八、逻辑操作符
关注的是真假。
&&,||
1.逻辑与&&
360笔试题:逻辑操作符的短路效果
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %d\\n b = %d\\n c = %d\\nd = %d\\n", a, b, c, d);
return 0; }
程序运行结果为多少?
剖析:左为假,则右边不再计算
举一反三:若将a的初值赋为1呐?
运行结果:
2.逻辑或||
完全类似的题目:
运行结果:
举一反三:若将a初值再改成0呐?
运行结果:
九、条件操作符
(exp1) ? (exp2) : (exp3)
十、逗号表达式
从左向右执行,整个表达式结果是最后一个表达式 的结果。
运行结果:
应用:
十一、下标引用,函数调用和结构成员
1.下标引用
进一步说明[ ] 是操作符:
运行结果:
2.函数调用
3.结构成员
上代码加强理解:
运行结果:
注:
十二、表达式求值
操作符可以说是为表达式而服务的,也影响着表达式的结果,主要体现在以下两方面:
1.表达式求值的顺序 ~ 操作符的优先级和结合性
2.类型转换 ~ 操作数在求值过程中可能需要转化为其他类型
1.隐式类型转换
隐式,即偷偷地,没法实在地看到。
这里要提到整形提升的概念及意义。
1.整形提升是什么?
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
整形提升规则,按照数据类型的符号位来提升。
2.整形提升的意义
小边从来不喜欢贴大段文字,但在这里觉得很有必要,有助于理解为什么要整形提升。
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
这可能也是寄存器读写很快的原因。
上代码感受:
看看你觉得结果是多少?
#include<stdio.h>
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d\\n", c);
return 0;
}
运行结果:
有了前面的铺垫,看到这个结果也不会感到震惊。
原理剖析:
巩固练习1:
#include<stdio.h>
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
return 0;
}
运行结果:只打印c
原理剖析:
巩固练习2:
运行结果:
2.算术转换
寻常算数转换:如果某个操作符的各个操作数属于不同的类型,那么其中一个操作数的必须转换为另一个操作数的类型,否则操作就无法进行。
代码感受:
转换规则:
3.操作符属性
关于优先级,这里值提供部分,有个感觉就好,记不住就加括号:
4.一些问题表达式
那是不是掌握了操作符的优先级及结合性及是否控制求值顺序,就一定能得到表达式的唯一结果了呐?也不是滴。下面来看一些问题表达式。
(1)代码1:
a*b + c*d + e*f;
由于*
比 +
的优先级高,只能保证,*
的计算是比 +
早,但是优先级并
不能决定第三个*比第一个+早执行。变量之间的牵连,会导致结果可能不同。
(2)代码2:
(3)代码3:
不同编译器下跑出结果不同:
求值应有唯一路径,那么这样代码就没什么意义。
(4)代码4
(5)代码5
很早小边就拿出过这段代码了
Linux平台下,编译结果
vs2013平台下,编译结果
调试起来,转到反汇编,简单看看即可:
本文完
相信小伙伴们会收获满满的。
以上是关于小边同学强势总结之C语言操作符的主要内容,如果未能解决你的问题,请参考以下文章