个人主页:Weraphael
✍作者简介:目前正在回炉重造C语言(2023暑假)
✈️专栏:【C语言航路】
希望大家多多支持,咱一起进步!
如果文章对你有帮助的话
欢迎 评论 点赞 收藏 加关注
- 算术操作符
- 位移操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用和结构成员
+ - * / %
%
,其他的几个操作符均可作用于整数和浮点数。但取模操作符的两个操作数只能是整数!最后返回的是整数之后的余数/
操作符,如果两个操作数都为整数,执行的是整数除法,如果想计算出小数,则除号两端至少有一个操作数是浮点数。<< 左位移操作符
>> 右位移操作符
注意:移位操作符移的是 补码的二进制位。位移操作符的操作数 只能是整数!
【正数案例】
左移操作符移位规则:不管左移多少位,左边丢弃,右边补0,且最后的结果是原码。
注:移位之后,
a
的值是不变的。
【负数案例】
解释如下:
最后有没有发现,左移有
×2
的效果。
首先右移运算分为两种:
- 逻辑位移(不讲,和左移操作符差不多)
左边补0,右边丢弃- 算术位移(常见 + 重点)
右边丢弃,左边用原该值的符号位填充
注:逻辑位移算术位移取决于编辑器,一般都是算术位移。
【解释如下】
注意:对于位移运算符,不要移动负数位,这个是标志未定义的。
& --- 按位与
| --- 按位或
^ --- 按位异或
注:位操作符操作的是补码的二进制位。它们的操作数必须是整数。
计算规则:对应的补码二进制位上,有0则为0,两个同时为1,才为1。
【解释如下】
计算规则:对应的补码二进制位上,有1则为1,两个同时为0,才为0。
【解释如下】
计算规则:对应的补码二进制位,相同为0,相异为1。
【解释如下】
要求:不能临时创建变量,交换两个变量的值。
【假设可以创建变量】
不创建临时变量应该怎么做呢?
#include
int main()
{
int a = 3;
int b = 5;
a = a + b;//此时a=8
b = a - b;//b = 3
a = a - b;//a = 5
printf("a = %d b = %d\n", a, b);
return 0;
}
但是上述的方法有一个缺陷,如果a
和b
的数字太大的时候,超出int
范围就会溢出。
因此可以采用按位异或操作符(高手解法)
#include
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;
}
【解释如下】
异或操作符的缺点
- 可读性差
- 效率不如使用临时变量的方法
- 异或只能针对整数的交换
赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的值,也就是你可以给自己 重新赋值。
int weight = 120; //初始化赋值
weight = 130; //不满意就赋值
//赋值操作符还能连续使用
int a = 10;
int x = 20;
int y = 30;
a = x = y + 1; //连续赋值(赋值顺序从右往左)
// 但是还是建议不使用连续赋值
//好的写法:
x = y + 1;
a = x;
目的就是为了简化代码。
+= a+=5实际上就是a=a+5
-= a-=5实际上就是a=a-5
*= a*=5实际上就是a=a*5
/= a/=5实际上就是a=a/5
%= a%=5实际上就是a=a%5
>>= b = b>>1可以写成b>>=1
<<= b = b<<1可以写成b<<=1
&= b = b & 1可以写成b&= 1
|= b = b | 1可以写成b|= 1
^= b = b ^ 1可以写成b^= 1
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置--、后置--
++ 前置++、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
真变假,假变真。
取地址操作符一般都是对一个变量取地址。
#include
int main()
{
int a = 10;
printf("%p\n", &a);//取出变量a的地址
//取出a的地址并存放在指针变量pc中,由于a是int类型,所以pc应该是int*
int* pc = &a;
//类似的,还有字符型
char ch = 'a';
char* pc = &ch;
//数组
char arr[10] = { 0 };
char* p2 = arr; //arr是地址首元素的地址,取出数组首元素的地址
char* p3 = &arr[0];//同上
//对于常量字符串而言
char* p4 = "abcdef"; //取的是a的地址
printf("%c", *p4); //*p4就是a
return 0;
}
这个操作符是配合
&
来使用的
首先取出变量a
的地址存放到指针变量pc
中,接着对pc
前加个*
叫做解引用,这时*pc
就等价于a
- 首先
sizeof
既是关键词,也是操作符。- 它可以计算变量大小、数组大小、类型大小。
sizeof
在计算变量名大小的时候,括号其实是可以省略的。
这从侧面上还能证明sizeof
不是函数,因为在调用函数时,括号是不能省略,但注意:sizeof
计算类型大小时,括号不可以省略。
很多人想当然以为a+3=13
,然后赋给b
,最后b
的值是13
,实际上是错误的!那为什么是错误的呢?
原因是:
sizeof
内部的表达式是不参与计算的,也就是说a+3
赋值给b
不会发生。所以b
的值还是一开始的5
,而为什么sizeof(b = a + 3)
的结果是2呢?原因很简单,a
是整型占4个字节,而a+3
中的3
也属于整型,也占4个字节,而b的类型是short
是2个字节,但a+3
的结果最终要放到b
中,若 整型要存储到短整型会发生截断,所以表达式最终赋值的空间还是b
说的算。
~
是对一个数的补码二进制所有位取反(1要变0,0要变1)
【解释如下】
#include
int main()
{
int a = 9;
a |= (1 << 4);
printf("%d\n", a);
return 0;
}
【代码解释】
那么问题来了,如何将最终目标改回9的二进制位呢?
#include
int main()
{
int a = 9;
a |= (1 << 4);
printf("%d\n", a);
a &= ~(a << 4);
printf("%d\n", a);
return 0;
}
【代码解释】
计算规则:先使用,再++
后置
++
,规则是先使用,则先使用a
的值赋给b
,所以b = 10
,接着再++
,意思是让a
自增1
,所以a = 11
计算规则:先++,再使用
前置
++
规则,先++
,所以a
先自增1
,所以a = 11
,接着再使用,就是将a = 11
赋给b
,所以b = 11
前置和后置--
可以参考++
3.14
是double
类型,而a
是int
类型,但是编辑器就报警了,原因是:“初始化:double
”转化到int
可能会丢失数据, 为了避免这种情况,只需要对3.14
强制类型转换。
>
>=
<=
!= 用于测试“不相等”
== 用于测试“相等”
这些关系运算符比较简单,没什么可以讲的,但要注意:在编程过程中,不要把==
(相等)和=
(赋值)写错
&& 逻辑与(并且)
|| 逻辑或(或者)
注:按位与(&
)和按位或(|
):它们是通过二进制计算的
而逻辑与(&&
)和逻辑或(||
):只关注真假
逻辑与(&&)
- 若
a
和b
同时为真
a&&b
的结果就为真- 若
a
和b
中至少有一个为假
a&&b
的结果就为假总结:两真为真,一假为假
逻辑或(||)
- 若
a
和b
同时为真
a||b
的结果就为真- 若
a
和b
其中一个为真
a||b
的结果就为真总结:一真为真,两假才为假
先看44行代码,它是逻辑与操作符。首先先计算
a++
,而后置a++
是先使用,后++
,所以a++
的值是0
,为假,对于逻辑与操作符,只要有一个为假,后面就没必要看了,但这里要注意的是,不管是前置++(–),还是后置++(–),它们都有副作用,虽然为假,但是a
还是会自增1,所以最后a=1
,b=2
,c=3
,d=4
如果把&&
换成||
,结果又会是如何呢?
首先先计算
a++
,刚刚说过了为假,a
自增了1
为1
,但是这里是逻辑或||
,一个假不能判定整个表达式全假,只有全假才算假,所以后面还要继续算,接下来++b
是先计算,后使用,所以b
自增1
为3
,注意到这里为止,后面d++
就没必要算了,逻辑或只要有一个为真,整个表达式都为真,所以打印结果就为a=1,b=3,c=3,d=4
exp1 ? exp2 : exp3
- 若
exp1
为真,则exp2
的结果就是整个表达式的结果,exp3
不计算- 若
exp1
为假,则exp3
的结果就是整个表达式的结果,exp2
不计算
例如:求两个数的最大值
exp1 , exp2 , exp3 , ...expN
- 逗号表达式,就是逗号隔开的多个表达式
- 逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果
首先从左向右依次执行,虽然
a > b
为假,但不会影响结果,接着把b + 10
的值赋给a
,则a = 12
,最后,c
的值就是最后b = a + 1
的值,所以b = 12 + 1 = 13
,也就是说c
的值为13
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数是传递给函数的参数。
例如:调用函数求字符串长度
大家可以参考这篇文章—>点击跳转
结构体 . 成员名
结构体指针->成员名
* + .