c语言-----操作符全家桶

各式各样的操作符详解

现在打下的所有基础,都在为你未来的能力上限做准备


在这里插入图片描述

1.算术操作符

2.原码,反码,补码

3.移位操作符(移(2进制)位操作符)

4.位操作符 (针对整数且为2进制位,均为补码计算)

5.赋值操作符

6.单目操作符

7.关系操作符

8.逻辑操作符

9.条件操作符

10.逗号表达式

11.下标引用,一个数组名,一个索引值

12.表达式求值—重点

1.算术操作符

对于除法操作符,两边的操作数都是整数,执行的是整数除,若想得到小数,除号两端至少有一个为浮点数/取模(取余),计算的是整除之后的余数
取模操作符(%),计算的是整除之后的余数,只能用整型类型的操作

2.原码,反码,补码

例如: a = 10

00000000000000000000000000001010-原码
00000000000000000000000000001010-反码
00000000000000000000000000001010-补码

正数的原码反码补码相同

如b= -10 ,下面写出b的原码,反码,补码

10000000000000000000000000001010-原码–按照一个数的正负,直接写出它的二进制表示形式
11111111111111111111111111110101-反码–原码的符号位不变,其它位取反(第一位是符号位)
11111111111111111111111111110110-补码-反码加1

补码变原码:先符号位不变,其它位按位取反,再+1

下图可以清晰总结原反补:
在这里插入图片描述

3.移位操作符(移(2进制)位操作符)

左移操作符:左边丢掉,右边补0

计算机在存储中存储的永远都是补码,所以在移位时,移动的是补码。

符号位(0是正数,1是负数)
整型占4个字节(32bit)
内存中存储的其实是:补码的二进制
所以在参与移位时,移动的都是补码–所以移位操作符的用法可以理解了

例如:

   a =10;
   a << 1;//2进制移位
  先写出10的补码:
    00000000000000000000000000001010
    00000000000000000000000000010100 (左移一位后的结果)
    但是这个过程a不变,变的是a向左移动的表达式这个结果变,a本身不变
    比如: a=10;b=a+2;b=12,但是a本身不变,还是10
    若想让a变化,可以写成 a>>=1;(a = a>>1

又比如:

int a = -10;
int b = a << 1;

先写出a的原反补:

10000000000000000000000000001010–原码
11111111111111111111111111110101–反码
11111111111111111111111111110110–补码

左移操作符:(补码)左边丢掉,右边补0
11111111111111111111111111101100–补码左移后的结果,是b的补码
10000000000000000000000000010011–计算过程
10000000000000000000000000010100–b的原码
由于打印(肉眼可见的)出来的都是原码,但是计算机存储的是补码,所以计算机要转换成原码再打印出来
总结,左移1位有×2的效果

右移操作符(看完左移操作符,就懂右移操作符了)
1)算术右移(平常见到)–也是计算机计算的方法
算数右移-右边丢弃,左边补原来的符号位

如 a =-1
100000000000000000000000000000001–a的原码
111111111111111111111111111111110–a的反码
111111111111111111111111111111111–a的补码

b= a>>1
11111111111111111111111111111111–a右移的结果,也就是b,但是a本身不变

2)逻辑右移(不怎么用)
逻辑右移-右边丢弃,左边直接补0

4.位操作符 (针对整数且为2进制位,均为补码计算)

& | ^
按位与,按位或,按位异或
& – 对应的2进制位有0则为0,两个同时为1,才为1

按位或
对应的二进制位,有1则为1,两个同时为0才为0

按(二进制)位异或
对应的2进制位,相同为0,相异为1

下面有一道面试题:

面试题:不能创建临时变量(第三个变量),实现两个正数的交换

使用异或操作符求解

先清楚两条计算规则:
1)a^a = 0
2)0^a = a

        a = a^b; //此时a相当于 a^b
        b = a^b;  //等价于 a^b^b == a^0 ==a ,所以b =a
        a = a^b;  //等价于a^b^a == a^a^b == 0^b ==b
        即a=b
        即可完成两个正数的交换

结论 :异或支持交换律

        异或虽好,不要贪杯
        1.可读性差
        2.效率不如使用临时变量的方法
        3.只能针对整数的交换

5.赋值操作符

赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的值,
也就是你可以重新赋值

好处:可以连续赋值

a= x = y+1 ; 也是从右到左开始赋值
但这种方法不易于理解,不易于调试
等同于:
x = y+1;
a = x;

6.单目操作符

1.+= 2. -=3. *= 4. /= 5. %= 6. >>= 7. <<=
易于理解

7.关系操作符

操作符有两个操作数,叫双目操作符,比如 1+3,+号为双目操作符,同理,只有一个操作数,叫单目操作符

!:逻辑反操作
-:负值
+:正值
&:取地址
&地址
> >= < <= != ==

一个等号叫赋值,两个等号叫判断

8.逻辑操作符 && -- 逻辑与 -- 并且 -- 不同于 &(通过二进制位)

在这里插入图片描述

判断闰年的规则就很好地说明这两个操作符 1,能被4整除,并且不能被100整除
2.能被400整除

 int main() 
 { 	
 int y = 2048; 
 	if ((y % 4 == 0 && y % 100 != 0) || (y %400 == 0)) 
 	{ 		
 printf("yes\n"); 
	}
  }
sizeof:操作数的类型长度(以字节为单位)
        sizeof - 是关键字,也是操作符
        功能是计算大小
~:对一个数的二进制按位取反(包括符号位)
按位取反(二进制数)(只能针对整数)
a = 0;
11111111111111111111111111111111 – ~a的补码
打印出来要变成原码,但是在计算机存储中仍然是补码
10000000000000000000000000000001 --~a的原码
打印出来就是 -1
--:前置,后置--
++:前置,后置++
*:间接访问操作符(解引用操作符)
(类型):强制类型转化

例如

         int main() 
       { 	
        int a = (int)3.14;
       //强制将double类型转换成int类型,相当于只是拿了整数部分 	printf("%d\n", a);

		 return 0;
 	    }

又如:

 int main()
{
	srand((unsigned int)time(NULL));
	//(unsigned int)--强制类型转换成无符号类型
	//NULL空指针
 
 } 强制类型转换是在万不得已的情况下才用的(强扭的瓜不甜)

布尔类型:

 补充:
                布尔类型:
                C99及以后引入的
                    布尔类型就是用来表示真假的类型 --  _Bool
                    只有true 和false 的赋值

总体来说,逻辑操作符如下:
在这里插入图片描述

9.条件操作符

exp1 ? exp2 : exp3 – 三目操作符
表达式1如果为真,表达式2计算,表达式2计算的就是整个表达式的结果
表达式1如果为假,表达式3计算,表达式3计算的就是整个表达式的结果
求两个数的较大值

int main()
{
	int a = 10;
	int b = 20;
	int c = a > b ? a:b;//(exp1 ? exp2 : exp3)
	printf("%d\n", c);
	三目操作符用于实现逻辑比较简单的操作
	return 0;

}

10.逗号表达式

10.逗号表达式
exp1 ,exp2,exp3,exp4,…expN
从左向右依次计算,整个表达式的结果是最后一个表达式的结果

int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);
最后决定c的是最后一个式子,从左到右表达式一次执行,执行的结果
如果改变最后一个表达式,那么也会影响c的值
	printf("%d\n", c);
}

11.下标引用--一个数组名,一个索引值

一段代码搞定:理解透彻

int main()
{
	int arr[10] = { 1,2,3,4,5 };
	printf("%d\n", arr[4]); //[] -- 下标引用操作符,操作数是 arr,4
两者缺一不可
	return 0;

12.表达式求值---重点

表达式求值的顺序一部分是由操作符的优先级和结合性决定的
同样,有些表达式的操作数在求值的过程中可能要转换为其他类型

12.1隐式类型转换

整型提升--针对类型小于整型的:char short
char short int long...
 1     2    4    8
整型提升是按照变量的数据类型的符号位来提升!!!

 由于char类型是一个字节,int类型是4个字节,所以用char类型无法完整表示int类型
 故会自动发生截断,只读取最后一个字节的二进制为,即8个二进制位


 现在讨论char类型的取值范围
最高位是符号位,符号位为0,表示整数,最大为011111111--127
符号位为1,表示负数,最小为
 char类型中 0,1,2...127,-128,-127,-126,...0,1,2,...127,-128...是一个圆环
 char类型中,127+1==-128-128+1=-127-127+1= -126
 所以打印出来是-126

//short -32768~32767
char–有符号的char的取值范围是 -128~127
无符号位的char的取值范围是0~255(因为第一位不再是符号位)
char -1字节-8比特位 有2^8次方种可能性

//以下例子说明整型提升的存在
int main()
{
char c = 1;
printf(“%u\n”,sizeof©);//1-char类型是1个字节
//由于+c是一个表达式,-c也是一个表达式子,所以会发生整型提升,提升后变成4个字节
printf(“%u\n”, sizeof(+c));//4-整型提升后,整型类型是4个字节
printf(“%u\n”, sizeof(-c));//4-整型提升后,整型类型是4个字节
// %u打印无符号十进制
}
//通俗的讲,整型提升是对字节不足的,进行字节补充,截断是字节超出范围的,把超出的高位截断
//12.2算数转换–大于int的都属于算数转换(隐式转换,也就是偷偷发生)
//如果某个操作符的各个操作数属于不同类型,
//那么除非其中一个操作数的转换为另一个操作数的类型,
//否则操作就无法进行。

//long double
//double
//float
//unsigned long int
//long int
//unsigned int
//int
//以上转换级别都是从下往上递增,即如果发生算数转换,一定是从下往上转换
//

//12.3操作符的属性
//1.操作符的优先级
//2.操作符的结合性
//3.是否控制求值顺序
//首先确定优先级,相邻操作按优先级高低计算
//优先级相同的情况下,考虑结合性

//1.优先级:相邻操作符才讨论优先级
//int main()
//{
// int a = 1;
// int b = 2;
// int c = 4;
// int d = a * 4 + b / 3 + c;
//
// //相邻才讨论优先级,无法确定 * 和 / 谁先算
// //相邻操作符优先级相同的情况下,考虑2.结合性
// return 0;
//}

补充:
算术转换:
long double
double
float
unsigned long int
long int
unsigned int
int
当连个不同类型的值比较或相加减时,默认从低到高转换,即向上转换

关注我,给你更多你意想不到的惊喜


在这里插入图片描述在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓富民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值