C语言 | 详解操作符

        在小学和中学时期,我们学过许多运算符,其中包括加、减、乘、除、开方、平方等等,而在C语言中,我们也有一些操作数据的符号,我们称之为操作符(运算符)。本文会将这些运算符 一 一讲解。

目录

一.算术操作符

二.移位操作符

1.左移操作符

2.右移操作符

 (1)逻辑右移

 (2)算术右移

三.逻辑操作符 

1.逻辑与 

2.逻辑或

3.逻辑非 

4.经典例题 

四.位操作符

 1.按位与

2.按位或

3.按位异或

4.经典例题

五.赋值操作符

六.单目操作符

1.sizeof操作符

2.++和--

七.关系操作符

八.条件表达式(三目运算符)

九.逗号表达式

十.隐式类型转换 

 1.无符号整型

2.有符号整型

3.经典例题

十一.算术转换


 一.算术操作符

        算术运算符主要有+(加)、-(减)、*(乘)、\(除)、%(求余)这些,而加减乘这三个与我们数学中的无异。下面主要给大家讲解 / 和 % 这两个操作符

#include <stdio.h>
int main()
{
	int a = 5;
	int b = 2;
	float c = 2.0;
	//除
	//1.操作符两边都是整型
	printf("%d\n", a / b);  //2
	//2.操作数有一边是浮点型
	printf("%f\n", a / c);  //2.5

	//求余(两边必须为整型,字符型也是特殊的整型)
	printf("%d", a % b);  //1
	return 0;
}

        在C语言中除号两边都是整型则采取整数除法,若有一边为浮点型,则会发生算术转换(这个概念本文后面会提及),比如上图中a会转换为浮点型,浮点型之间的除法执行浮点数除法,因此结果为2.5。

注:取余操作符的操作数只能是整型。

二.移位操作符

<<        左移操作符 

>>        右移操作符

移位操作符中的位代表的是二进制位

1.左移操作符

规则:左边抛弃,右边补零。

 如下图:

 ​​​​

 注:数据在内存中是以补码的形式存放,正数的原码,反码,补码相同,在一个有符号数中,我们用最高位表示数的符号,我们称这一位为符号位,0表示正数,1表示负数。(这里仅仅简单提及一下,后面会出一篇博客详细讲解数据的储存方式)

下面用代码验证一下上图:

#include <stdio.h>

int main()
{
	int a = 1;
	printf("%d\n", a << 1);
	return 0;
}

 果然结果正是我们预想的数值2。

2.右移操作符

右移操作符分为两种

1.逻辑右移

        左边补零,右边丢弃

2.算数右移

        左边补符号位,右边丢弃

 (1)逻辑右移

 (2)算术右移

         C语言标准中并没有规定用哪一种,所以每个编译器定义的标准可能不同,我这里通过VS2022版本测试结果为-1,是情况二,算术右移。(注:以上所有测试条件都在32位环境中测试)

 注:移位操作符不能移动负数位,比如 a << -1,这种写法是错误的。

  

三.逻辑操作符 

&&        逻辑与

 ||          逻辑或

 !        逻辑非

1.逻辑与 

 逻辑与是这么定义的

1 && 0  -----  0

0 && 1  -----  0

1 && 1  -----  1

只有两个操作数都为非零(真)结果才为1(真)

 2.逻辑或

逻辑或是这么定义的

1 || 0  ------  1

0 || 1  ------  1

0 || 0  ------  0

只要两个操作数都为零(假)的时候结果才为0(假) 

3.逻辑非 

逻辑非是这么定义的

! 1 ------  0

! 0 ------  1

即1(真)取非则成0(假),0(假)取非则成1(真) 

4.经典例题 

下面有一道经典笔试题(from 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;
}
//程序输出的结果是什么?

 这道题的答案是:

         有很多小伙伴可能就疑惑了,为什么不是1 3 3 5呢,而是1 2 3 4,这是因为在逻辑与中,有一个有意思的现象,我们称之为短路现象,即当与左边的操作数为假的时候,整个表达式的结果就为假,后面的表达式就不进行计算了,什么意思呢?按本题思路来看,当a++为假的时候,整个表达式结果为0(假),如题这里a是后置++,且a的值恰好为0(假),因此后面的表达式就不进行运算,就得到了如上图的答案了。

        同样,逻辑或也有这样的现象,当逻辑或的左边表达式结果为1(真),整个表达式的结果变为1(真),后面的表达式同样也不用参与运算。

四.位操作符

所谓的位操作符中的位也指的是二进制位,具体操作符如下

&       按位与

|        按位或                

^       按位异或 

注:他们的操作数也必须都为整数

 1.按位与

        与和逻辑与类似,不过按位与是将二进位每一位按位与。比如1和3按位与

 代码测试结果如下:

 如我们上图推测结果一样,结果为1。

2.按位或

        按位或也是与逻辑或类似,他们计算的都是对应的二进制位,如下1按位或3

 代码测试结果如下,依旧和我们算的一样,结果为3

3.按位异或

按位异或则是指将两个数对应二进制位进行运算,如果相同则为0,相异则为1,如下图

 始终记住相异为1,相同为0,下面代码也证实了上图

int main()
{
	int a = 1;
	int b = 3;
	printf("%d\n", a ^ b);
	return 0;
}

 结果也正是我们推导的2。

4.经典例题

 小试牛刀,下面有一道经典面试题:

 不能创建临时变量,实现两个数的交换(这两个数可能会很大)

看到这题,很多人可能会想到将两个变量相加然后,相减达到交换目的,如下代码

int main()
{
	int a = 1;
	int b = 3;
	a = a + b; //4
	b = a - b; //1
	a = a - b; //3
	return 0;
}

         但是题目中有一条说明,这两个数可能会很大,这说明什么呢,假如这两个数定义为int型,那么假如这两个数都很大,如果相加,最终很有可能存不下这么大的数据,最后导致数据丢失,造成结果不准确的后果。以下就有一种方法可以保证不会造成数据丢失

int main()
{
	int a = 1;
	int b = 3;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a=%d, b=%d\n", a, b);
}

分析:假设数据只有8位,方便运算

a的补码:0000 0001

b的补码:0000 0011

a=a^b:      0000 0010   ------a = 2

b=a^b:      0000 0001   ------b = 3

a=a^b:      0000 0011    -----a = 1

这种方法非常巧妙,不需要相加,因此不可能造成数据丢失。

五.赋值操作符

        这个操作符很简单,但新手又很容易犯错误,因为这个操作符和数学中的相等是同一个符号,而C语言中的相等用两个等于号表示(“==”)。

=      赋值操作符

此外还拓展了符合赋值操作符,也就是把赋值操作符和以上操作符的结合

int a = 0;

+=      a += 1;            ----- a = a + 1;

-=       a  -= 1;            ----- a = a  - 1;

*=       a  *= 1;           ----- a = a * 1;

/=       a  /= 1;            ----- a = a / 1;

%=     a %= 1;          ----- a = a % 1;

>>=    a >>= 1;         ----- a = a >> 1;

<<=    a <<= 1;         ----- a = a << 1;

&=      a &= 1;          ----- a = a & 1;

|=       a |= 1;            ----- a = a | 1;

^=      a ^= 1;           ----- a = a ^ 1;

六.单目操作符

所谓单目操作符就是只有一个操作数的操作符

!           逻辑反操作

-           负值

+           正值

&           取地址

sizeof      操作数的类型长度(以字节为单位)

~           对一个数的二进制按位取反

--          前置、后置--

++          前置、后置++

*           间接访问操作符(解引用操作符)

(类型)       强制类型转换

 以上操作符都为单目操作符,本文重点讲下列操作符

1.sizeof操作符

        有很多新手甚至书籍会将这个当作一个函数,实际上,这只是一个操作符,如何证明这一点呢?我们都知道函数的调用后面必须得加小括号,我们可以测试以下sizeof后面不加小括号是否可以运行便可。

         可以看到,我们得程序是可以写出来的,这也证实了sizeof并不是一个函数,而是一个运算符。

2.++和--

在C语言中,有前置++和后置++,当然也有前置--和后置--,下面则是前置和后置的区别

int a = 0;

int b;

前置:

b = ++a; ------ a += 1;  b = a;

后置:

b = a++; ------ b = a; a += 1;

 总体来说,前置++便是先加后用,后置++便是先用后加,--也同理。

七.关系操作符

关系操作符:

>          大于

<          小于

>=        大于等于

<=        小于等于

!=        不等于

==        等于

 以上的关系操作符最后的值均为1或0

八.条件表达式(三目运算符)

表达式1 ? 表达式2 :表达式3;

条件表达式与分支语句if极为相似,可以说功能是一致的

如果表达式1的值为真,整个表达式的值为表达式2的值

如果表达式1的值为假,整个表达式的值为表达式3的值

简单的运用以下,如代码

由于a小于b成立,则表达式的值为a的值,然后赋值给c

int main()
{
    int a = 3;
    int b = 4;
    int c = 0;
    c = a < b ? a : b; 
    //最后c的值为3
    return 0;
}

 九.逗号表达式

语法:

表达式1,表达式2,表达式3.……表达式n

 注意:逗号表达式会从第一项开始运算,整个逗号表达式的值为最后一项。

int main()
{
    int a = 2;
    int b = 5;
    int c = (a++, b += a, c = b);
    return 0;
}

        根据我们上面的定义,我们先计算a++,再计算表达式b += a,最后计算c = b,整个表达式的值为最后一项。即c的最终结果为8。

十.隐式类型转换 

C的整型算术运算总是至少以缺省整型类型的精度来进行的。

首先我们要提及以下整型提升的概念

整型提升:在表达式计算时,各种整型首先要提升为int类型,如果int类型不足以表示则要提升为unsigned int类型;然后执行表达式的运算。

表达式的整形运算要在CPU相应的运算器内进行,CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

因此即使是两个字符型相加,也会进行整型提升。那么如何进行整型提升

 1.无符号整型

比如 char ch1 = 1;

变量ch1的二进制补码中只有8个字节,

0000 0001

在发生整型提升后,高位补零,直至32个比特位

2.有符号整型

比如 char ch2 = -1

变量ch2的二进制补码中也只有8个字节

1111 1111

在发生整型提升后,高位补符号位,ch2的符号位是1,所以补1直至32位。

3.经典例题

猜猜下面四个表达式最终输出结果:

int main()
{
	char c = 1;
	printf("%d\n", sizeof(c));
	printf("%d\n", sizeof(c + 1));
	printf("%d\n", sizeof(c = c + 1));
	printf("%d\n", c);
	return 0;
}

最终结果如下图:

 您猜对了吗?

第一个大家应该都能想到,char类型的大小是一个字节

第二个进行了整型提升,故结果为4

第三个其实根本就没有进行运算,只是判断了c的类型,故为1(sizeof里的表达式根本不会进行运算)

第四个由于第三个根本没有进行运算,所以答案还是为1

十一.算术转换

如果两个操作数是不同的类型,其中一个操作数会自动转换为另外一个操作数的类型

long double

double

float

unsigned long int

long int

unsigned int

int

         如上列表,由下往上转换,如int类型加上一个float类型,最终的结果为float类型的值。不过在转换过程中很可能会出现精度丢失的情况。

        以上就是本文的全部内容了,看到这里,如果觉得小编写的还不错就三连一下吧,感谢支持,我会继续向大家更新更好的内容。

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值