操作符与表达式

操作符

算术操作符/

当 进行7/2时答案只会是3,将7换成7.0或2换成2.0,或者两者都换成小数结果就是3.5。

移位操作符

整型的二进制表示:

原码,反码,补码

符号位为0,表示正数,符号位为1表示负数。(符号位在最高位,也就是第一位)

正整数

正整数的原码、反码、补码都相同

负数

原码变反码:原码的符号位不变,其他位按位取反

反码变补码:反码+1

左移操作符<<

把a的2进制位写出来,左边丢弃右边补0

这时可得a的大小由-4变成了-8

a的三种码:

右移操作符>>

1、逻辑右移

右边丢弃,左边补0

2、算数右移

右边丢弃,左边补原符号位

绝大部分编译器右移采用算数右移

对于移位操作符,不要移动负数位,这是标准未定义的

位操作符

& 按位与

两个2进制序列中,如果有0则为0,两个同时为1才为1。

第3行就是前两行按位与的结果

| 按位或

两个2进制序列中,如果有1则为1,两个同时为0才为0。

第3行是前两行按位或的结果

^ 按位异或

异或的运算规律,相同为0,相异为1。

第3行是前两行按位异或的结果

小练习

不能创建临时变量(第3个变量),实现两个数的变换

这种方法固然可行,但当a ,b的数值过大时,就不太适用

我们今天学习操作符,或许可以用操作符来解决这个问题

就像 3^3

5^5

他们都数字相同,所以异或的结果也都是0.

3^5 结果是6 110

如果我们这样操作3^5^5:

5^5的结果是0,我们又可以发现3^0的结果还是3

所以 3^5^5的结果就是3

则3^5^3 的结果就是5

我们就可以把3^5看做密码,3、5任意一个数与密码异或就会得到另一个数。

那么这道题就迎刃而解:

#include<stdio.h>
int main()
{
	int a = 9;
	int b = 6;
	a = a ^ b;
	b = b ^ a;
	a = a ^ b;
	printf("%d %d \n", a, b);
	return 0;
}

1代码指的是讲密码赋值给a

2代码指的是将原来的b与赋值后的a异或再赋值给b,结果就会是原来的a

3代码指的是将赋值后的b(值为原来的a)与密码相异或得到b房,赋值给a

这个是1代码

这个是2代码

这个是3代码

赋值操作符

复合赋值符

单目操作符

! 逻辑反操作

这里的flag = 0,为假,!flag就为真

& 取地址符号

int*pa = &a 就是把a的地址存放在pa里面

*pa 叫解引用,通过a的地址找到a,也可以通过改变pa的值来改变a的值

只存在 *pa = 2 不存在pa = 2

这种给100强制分配一个空间,这种指针属于野指针

 ~按位取反

把变量数值的补码按位取反

第一行是a 的补码,第二行是~a的补码,第三行是~a的反码(补码-1),第四行是~a的原码(反码符号位不变,其他位按位取反)

我们观察这段二进制序列,现在的需求是将第三位的0换成1,且其他位不变。

这时只需按位或一个第二行的这种序列就可以实现

第二行也可以表示为1向左移动2位

表示为 a = a | ( 1<<2)

当我们需要设置第n位时就可以表示为1向左移动(n-1)位

改为0的代码类型

把a的第n位置改为0 a = a &~(1

前置与后置++ --

sizeof

求变量(类型)所占空间的大小。

这种sizeof后面放类型也省略的做法是错误的

我们再来观察这一段代码

这里的a+5打印出来的结果为什么会是2?

a 是int类型,a+5也同样是int类型,但s却是short类型,只有2字节的空间,但必须要把int类型的值放在short类型的变量中去,这时就会发生“截断”(把4个字节砍掉2个字节)再放进去,这样打印的就是short类型就是2.

sizeof()内部放的表达式不计算的

关于如何截断

上面是2的二进制位,中间是5的二进制位,下面是两个加起来的二进制位,将他们加起来的数需要进行截断,取得当然是低的字节,否则得出来的数永远不准确

就是这样

我们再观察这段代码

这里的(2)(4)打印的结果都是4

(2)的指针是int类型的,(4)的指针是char*类型的可能有人会觉得char*类型的指针打印出来的结果就是2,其实不然。

所有指针类型大小都是固定的4字节。(前提是在x86环境下,x64环境就是8字节)

(类型)

类型强制转换

关系操作符

逻辑操作符

注意,上强度了

这段代码

& 的规则:有0就为0,两个同时为1,才为1

这里的a++是0,0为假,++b就不用算,也为假 a++ && ++b,整体都为假了,后面也不用算了。

所以结果就是 1 2 3 4

在看下这段代码

结果显而易见是 2 3 3 5

再看这段代码

结果还是2234

1334

三目操作符

可以改成

逗号表达式

从左向右依次计算

这个代码就是前面算的值赋给d,最后再算d是否 >0

这个代码左边有点冗余,换成右边就刚刚好

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

下标引用 []

概念:
用于访问数组或容器中的指定位置元素
本质上是通过指针偏移来取值。

示例:

arr[2] // 访问数组第 3 个元素

函数调用 ()

概念:
用于调用函数并传入参数,执行函数体并返回结果。

示例:

add(3, 4) // 调用函数 add,并传入参数 3 和 4

结构成员访问 .->

.(点)概念:
用于通过对象或结构体变量访问其成员。

->(箭头)概念:
用于通过指向对象的指针访问其成员。

s.name // 通过对象访问成员 
p->name // 通过指针访问成员(等价于 (*p).name)

算术转换

整型提升

整型提升是按照变量的数据类型的符号位来提升的

这里的a b 计算前都将二进制序列进行了截断,随后再相加

要进行计算时就需要整型提升,补充符号位,这里两个数的符号位都为0 ,所以就补0,如果符号位是1就会全补1

讲2者相加后值赋给c,但c是char类型所以需要截断

接下来我们要进行打印

但%d打印的是十进制的有符号整数

这里的c不够,我们就需要整型提升得补码,-1得反码,再按位取反得原码

再看这段代码

打印出来的结果是只有c,因为a b 应该char 类型 一个short 类型,打印就需要整型提升,提升后与原数值不符

无符号的整型提升,高位直接补0

再来看这段代码的运行结果

只有第一个结果是1,因为这里的c只要是表达式就会涉及运算,就会涉及整型提升,无论是否有意义。

转换优先级

当两个类型不一样,转换方向总是向上转成更宽的类型

类型等级类型
1long double
2double
3float
4unsigned long long
5long long
6unsigned long
7long
8unsigned int
9int(包含 char/short)

操作符的属性

1、操作符的优先级

2、操作符的结合性

3、是否控制求值顺序

像第一个两个相邻的操作符,先算优先级高的操作符,而第二个就不确定了

操作符的优先级

优先级操作符含义结合性
1() [] -> . ++ --括号调用、数组下标、成员访问、后缀自增/自减左到右
2++ -- + - ! ~ * & (type) sizeof单目运算符、强转、取地址、逻辑/位非等右到左
3* / %乘法、除法、取模左到右
4+ -加减左到右
5<< >>位移左到右
6< <= > >=比较大小左到右
7== !=相等/不等左到右
8&按位与左到右
9^按位异或左到右
10``按位或
11&&逻辑与左到右
12``
13?:三目运算右到左
14= += -= *= /= %= <<= >>= &= ^= `=`赋值及复合赋值
15,逗号表达式左到右

还有一些有问题的表达式

这个也是,不能确定操作数什么时候准备好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值