操作符详解(入门)

目录

序言

一.算术操作符

二.移位操作符

1.左移操作符<< 

2.右移操作符>>

三.位操作符

 四.赋值操作符

五.单目运算符

1.sizeof操作符

 2.前置/后置++ --

3.!逻辑反操作

六.关系操作符 

七.逻辑操作符

八.条件操作符(三目操作符)

九.逗号表达式

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

十一.复杂表达式


序言

  本篇文章主要介绍C语言中不同类型的操作符,它们的功能,以及一些需要注意的小细节.

一.算术操作符

 +    -   *   /   %(取余)

算术操作符和我们平时进行数字运算时用的算术符号功能完全相同,这里不多赘述,只谈一些细节.

1.上述符号都是二元操作符,即针对的是两个操作数.一元只需要一个操作数比如+1,起到强调其为正数的作用.

2.除了%运算符外(需要用fmod函数),另外的操作符都可运用在整数,浮点数上,当int类型和float类型进行/运算时,运算结果将会是float类型的.

3.两个整数相除,答案将会舍弃小数部分输出,比如1/2,得到0.5,舍弃掉小数部分,实际上只会输出0.

4.当/和%运算符作用在负操作数上,结果将会变得无法确定,按照C89标准,-9/7可以取-1也可以取-2,但在C99标准时,将会向靠近0的部分进行取值,-9/7会得到-1.

二.移位操作符

<< 左移操作符
>> 右移操作符   (只针对整数)

1.左移操作符<< 

(左边抛弃,右边补0) 从结果上看,相当于乘2的效果.像是194左移变成1940,相当于乘10.

2.右移操作符>>

1.逻辑移位
 对应上述左移的操作,所有二进制位向右移动,左边用0填充.
  不考虑符号位的影响,负数移位后,符号号位由1变成0,导致变成正数或者0

2.算术右移(vs2019中采用的是算术右移)

左边用符号位填充,右边丢弃,保留正负性

也可以理解为符号位保持不变,同时用位移前符号位的数字来填充空位

注意:千万不要移动负数位!!!!!

三.位操作符

&   // 按位与
|    // 按位或
^   // 按位异或
~ //按位求反运算符  (将二进制每一位取反)
注:他们的操作数必须是整数
上图为《明解C语言》书中对这四种位操作符的解释,注意它们的对象都是二进制形式(补码).
这里需要重点理解的是 逻辑异或操作符,相异为1,相同为0.
相同的两个数异或必为0,0与任何数异或必定为其本身(由上表可知)

通过逻辑异或操作符^,我们就可以进行些好玩的操作,比如在不创建第三个变量的情况下,将变量a,b的值发生交换.(甚至无浪费更多空间)

同样我们还可以实现不使用+-*/符号,实现将两个数相加.

比如十进制的15和7相加,实际上是没有进位的12,与进位的10,两者相加得到的22.

二进制也可以进行同样的实现,a ^ b得到不进位的数字,(a & b)<<1 得到进位后的数字

当然为了避免在接下来异或操作中,依旧存在进位,我们要重复操作,直到(a & b)<<1 == 0停止.(意味没有进位)

Lg.          a=0101(5)     b = 0011(3)

第一次    0110(a ^ b)   0010 [(a&b)<<1]   

第二次    0100(a ^ b)   0100 [(a&b)<<1]

第三次    0000(a ^ b)   1000 [(a&b)<<1]

第四次    1000(a ^ b)   0000(结束循环)

得到答案1000(8)代码如下:

int Add(int num1, int num2) {
    // write code here
    while (num2 != 0)
    {
        int tmp = num1 ^ num2;
        num2 = (num1 & num2) << 1;
        num1 = tmp;
    }
    return num1;
}

同样,逻辑与和逻辑或操作符也有很多有趣的操作,这里只举一个例子,比如统计一个数的二进制中有多少个1,和多少个0.

#include <stdio.h>
//统计二进制中1的个数
int Count_one_bit(int x)
{
	int cnt = 0;
	while (x)
	{
		x = x & (x - 1);
		cnt++;
	}
	return cnt;
}
//统计二进制中0的个数
int Count_zero_bit(int x)
{
	int cnt = 0;
	while (x + 1)
	{   
		cnt++;
		x = x | (x + 1);
	}
	return cnt;
}
int main()
{
	int x = 0;
	scanf("%d", &x);
	int num1 = Count_one_bit(x);
	int num2 = Count_zero_bit(x);

	printf("%d %d", num1, num2);
	return 0;
}

 四.赋值操作符

=  基本赋值操作符
+=    -=    *=    /=    %=    >>=    <<=    &=   |=     ^=   复合赋值操作符
在许多编程语言中,赋值是一种语句,但在C语言中,C是一种与加法相同的运算, 赋值操作产生结果.
比如
int a; 
a = 93.33f;
最后得到a的值是93,而不是93.33
值得一提的是,赋值操作符要求左边操作数必须为一个 左值(也就是一个变量,类似10,2*i等等都不是一个左值),在初学的时候,很多人会无法区分== 与 = 的区别,即便debug很久也没发现 ,因此采用10 == i将会比i == 10更好,不同于==操作符,10 = i 是无法通过的.
注意:表达式i * = j + k  [ i = i * (j + k)] 与  i = i * j + k两个式子是不一样的,赋值运算符往往会涉及操作符优先级,方向问题.

五.单目运算符

!             逻辑反操作
-             负值
+           正值
&           取地址
sizeof     操作数的类型长度(以字节为单位)
~             对一个数的二进制按位取反
--            前置、后置 --
++         前置、后置 ++
*             间接访问操作符 ( 解引用操作符 )
( 类型 )     强制类型转换
这里只详细谈一下sizeof 与 前置后置++ -- ,和逻辑反操作!,另外的几个操作符我们比较常见,细节上也比较少需要注意的地方,以后遇到再进行补充.

1.sizeof操作符

sizeof操作符可以求解类型名,对象,常量等的字节大小

 

图片来自《明解C语言》一书
在C语言中,sizeof(short) <= sizeof(int) <=sizeof(long),根据不同编译器所决定
接下来,我们看一段这样的代码,来进一步加深对sizeof操作符的理解

数组名一般是数组首元素的地址 ,传参时,也是传的首元素的地址,我们可以用指针去接收它,但在sizeof(数组名)中,求的是整个数组的大小.

我们再看一段这段代码,a没有显示++,这是为什么呢?

一般表达式的运算是在运行时执行的,而sizeof是一个编译阶段就执行的运算符,在其内的任何运算都不执行. 所以a并没有++.

 2.前置/后置++ --

首先必须明确, 无论是前置或者是后置操作,最终都改变操作数的值
唯一不同在于,
前置操作是先改变值,后使用;
后置操作是先使用,后改变值.
我们可以看下面这一段代码,++a先改变了a的值,a此时变成11,然后赋给了y,而b++则不同,b先赋值10给x,然后b再加1,但由于没保存,因此b的值不发生改变.

3.!逻辑反操作

非0则变为0(真转成假);0则变为非0(假转成真)

补充:德摩根定律

对各条件取反,然后将逻辑或变为逻辑与(逻辑与变为逻辑或),再加上取反,两者是等价的.

比如x <= 3 && y >=6  <---------->  !(x > 3 || y < 6)两者是等价的

其实也比较好理解,&&逻辑与在数学上和交集概念类似,||逻辑或在数学上和并集概念类似,!则是取补集.读者通过下面的图可以尝试自己加深理解.

六.关系操作符 

>
>=
<
<=
!=        用于测试 不相等
==       用于测试 相等
虽然简单明了,但逻辑判断上可是不可或缺的,所以使用上也要注意,比如==和=两者的区别.

七.逻辑操作符

&&        逻辑与
||           逻辑或
简单概括,
逻辑与,是从左往右逐一判断条件,只要有一个为假,后面条件都不再判断,直接为假,反之才为真;
而逻辑或,也是从左往右逐一判断条件,只要有一个为真,后面条件都不再判断,直接为真,反之才为假.
我们看下下面这段代码,加深一下理解

a++为后置++,先使用,意味着a为0,0代表假,所以后面所有的条件都没判断,b,d的值都没有改变

可以猜想,当逻辑与换成逻辑或,a,b的值都会改变,而d的值不会改变,可以想一下为什么?

八.条件操作符(三目操作符)

exp1 ? exp2 : exp3

实际上和if ...else ...相同功能,不过更加简便.

九.逗号表达式

exp1 , exp2 , exp3 , …expN
从左往右依次进行计算, 整个表达式的结果只和最右边的表达式有关.

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

 [ ] 下标引用操作符  

数组访问下标,实际上是对指针进行移动,然后解引用访问相应的值

 ( ) 函数调用操作符
能够接受一个或者多个操作数
访问一个结构的成员
. 结构体 . 成员名
-> 结构体指针 -> 成员名

十一.复杂表达式

复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序.
所以了解不同操作符优先级,结合性也是十分重要的,在此贴上《明解C语言》中关于操作符优先级的图,具体更为详细的图,可以去网上进行搜索.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值