文章目录
-
- 前言
- 一、操作符的分类
- 二、二进制和进制转换
- 三、原码,反码,补码
- 四、算数操作符
- 五、移位操作符
- 六、位操作符
- 七、赋值操作符
- 八、单目操作符
- 九、关系操作符
- 十、条件操作符
- 十一、逻辑操作符
- 十二、逗号表达式
- 十三、下表访问[],函数调用()
- 十四、结构体成员访问操作符
-
- 14.1结构体
- 14.2结构体访问操作符
-
- [14.2.1 结构体成员的直接访问`.`](#14.2.1 结构体成员的直接访问
.
)
- [14.2.1 结构体成员的直接访问`.`](#14.2.1 结构体成员的直接访问
- [14.2.2 结构体成员的间接访问 `->`](#14.2.2 结构体成员的间接访问
->
)
- 十五、操作符的属性:优先级与结合性
-
- [15.1 优先级](#15.1 优先级)
- [15.2 结合性](#15.2 结合性)
- 十六、表达式求值
-
- [16.1 求值规则](#16.1 求值规则)
- [16.2 短路求值特性](#16.2 短路求值特性)
- [16.3 顺序点(Sequence Point)](#16.3 顺序点(Sequence Point))
- [16.4 表达式求值注意事项](#16.4 表达式求值注意事项)
- 结语
前言
用一篇文章彻底总结C语言操作符。请耐心看完哦!!!(该博客适合复习时候,建立框架)
一、操作符的分类
算数操作符:
+
,-
,*
,/
,%
移位操作符:
<<
,>>
位操作符:
&
,|
,^
赋值操作符:
=
,+=
,-=
,*=
,/=
,%=
,<<=
,>>=
,&=
,|=
,^=
单目操作符;
!
,++
,--
,&
,*
,+
,-
,~
,sizeof
,(类型)
关系操作符:
>
,>=
,<
,<=
,==
,!=
逻辑操作符:
&&
,||
条件操作符:
?:
逗号表达式:
,
下标引用:
[]
函数调用:
()
结构成员访问:
.
,->
二、二进制和进制转换
其实我们经常能听到2进制、8进制、10进制、16进制这样的讲法是有什么深刻的含义吗?
其实2进制、8进制、10进制、16进制是数值的不同表现形式罢了。
比如数值15的各种进制的表现形式:
15
的2
进制:111115
的8
进制:1715
的10
进制:1515
的16
进制:F
我们重点解释一下二进制:
首先我们还是得从10进制讲起,其实10进制是我们生活中经常使用的,我们已经形成了很多尝试;
- 10进制中满10进1
- 10进制的数字每一位都是由0~9的数字组成
其实二进制也一样 - 2进制中满2进1
- 10进制的数字每一位都是由0~1的数字组成
注意;这几种进制只是最常用还有其他进制的,例如星期是7进制,月份是12进制
三、原码,反码,补码
四、算数操作符
这些操作符都是双目操作符
注:操作符也被叫做运算符是不同的翻译,意思是一样的
4.1+
和-
+
和-
用来完成加法和减法。
+
和-
都是有两个操作数的,位于操作符两端的就是它们的操作数,这种操作符也叫做双目操作符。
c
#include<stdio.h>
int main()
{
printf("%d\n", 35 + 35);
int a = 20;
int b = 20;
printf("%d\n", a + b);
printf("%d\n", a + 33);
printf("%d\n", a - b);
printf("%d\n", a - 33);
return 0;
}
4.2*
*
用来完成乘法。
同上,*
也是双目操作符。
c
#include<stdio.h>
int main()
{
printf("%d\n", 35 * 35);
int a = 20;
int b = 20;
printf("%d\n", a * b);
printf("%d\n", a * 33);
return 0;
}
4.3/
/
用来完成除法。
除号的两端如果都是整数,执行的是整数除法,如果要计算出小数的效果,那么除号的两端至少有一个数得是浮点数
同上,/
也是双目操作符。
如果计算小数除法需要限制几位小数只需%lf
在lf前加上.
加上数字,就是几位小数。、
数字小数默认是double类型,如果需要float类型,可以使用强转,或者在数字后面加上f
c
#include<stdio.h>
int main()
{
printf("%d\n", 35 / 35);
int a = 20;
int b = 20;
printf("%d\n", a / b);
printf("%lf\n", a / 33.0);
return 0;
}
4.4%
%
用来完成求模运算,即返回两个整数相除的余数。这个运算符只能用于整数,不能用于浮点数。
同上,%
也是双目操作符。
c
#include<stdio.h>
int main()
{
int a = 7 / 2;
int b = 7 % 2;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
负数求模的规则是,结果的正负号由第一个运算数的正负号决定。
c
#include<stdio.h>
int main()
{
printf("%d\n", 11 % -5);
printf("%d\n", -11 % -5);
printf("%d\n", -11 % 5);
return 0;
}
五、移位操作符
<<
左移操作符
>>
右移操作符
==注:==移位操作符的操作数只能是整数
5.1左移操作符
移位规则:左边抛弃,右边补0
c
#inlcude<stdio>
int main()
{
int a = 10;
int b = a << 1;
printf("%d\n",a);
printf("%d\n",b);
return 0;
}

5.2右移操作符
移位规则:
逻辑右移:右边抛弃,左边补0
算术右移:右边抛弃,左边补符号位
c
#inlcude<stdio>
int main()
{
int a = 10;
int b = a >> 1;
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
逻辑右移:
算术右移:
c
#inlcude<stdio>
int main()
{
int a = -10;
int b = a >> 1;
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
逻辑右移:
算术右移:

==警告:==位移操作符不要移动负数位,这是标准未定义行为
c
a = 10;
b = a << -1//error
六、位操作符
6.1&
该操作符是按位与,具体计算过程是将补码的每一位进行与计算
例:
c
-3 & 5;
-3
的补码是11111101
,5
的补码是00000101
然后按位与计算就是一位一位进行与操作,比如说-3
的第一位是1
,5
的第一位是0
,那么进行与操作计算结果的第一位就是0
然后一直到最后一位,最后的结果是00000111
这个是补码,转化为10进制就是7
。
6.2|
该操作符是按位或,具体计算过程可以参照&
操作符的过程,就是对每一位进行或操作。
6.3^
该操作符是按位异或,具体计算过程可以参照&
操作符的过程,就是对每一位进行异或操作。(相同时为1,不同时为0。)
6.4~
该操作符是按位取反,具体计算过程可以参照&
操作符的过程,就是对每一位进行取反操作。
七、赋值操作符
7.1=
在变量创建的时候给一个初始值叫做初始化,在变量创建好后,再给一个值,这叫做赋值。
c
int a = 100;//初始化
a = 200;//赋值,这里使用的就是赋值操作符
赋值操作符是一个随时可以给变量赋值的操作符。
7.1.1连续赋值
赋值操作符也可以连续赋值,如:
c
int a = 3;
int b = 5;
int c = 0;
c = b = a+3;//连续赋值,从右向左一次赋值。
c语言虽然支持那种连续赋值,但是写出的代码不容易理解(不推荐连续赋值),建议还是拆开来写,这样方便观察代码的执行细节(方便阅读代码或者找出错误)。
7.2复合赋值
在写代码的时候,我们经常可能对一个数进行自增或自减如下代码
c
int a = 10;
a = a + 3;
a = a - 2;
这样代码c语言给提供了更加简便的方法
c
int a = 10;
a += 3;
a -= 2;
c语言提供了复合赋值符,方便我们编写代码,这些赋值符有:
c
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
八、单目操作符
单目操作符 ------ 只有一个操作数
++
,--
,+
(正),-
(负)!
(逻辑非),&
(取地址操作符),*
(解引用操作符),~
(按位取反),sizeof
,(类型)
就是单目操作符。
8.1++
和--
++
是一种自增操作符,又分为前置++
和后置++
。
8.1.1前置++
c
int a = 10;
int b = ++a;
printf("a = %d,b = %d",a,b);
使用口诀:先+1,后使用
a原来是10,先+1,后a变成11,再使用就是赋值给b,b得到的也是11,所以最后a,b都变成11了
相当于下面的代码
c
int a = 10;
a = a + 1;
b = a;
printf("a = %d,b = %d",a,b);
8.1.2后置++
c
int a = 10;
int b = a++;
printf("a = %d,b = %d",a,b);
使用口诀:先使用,后+1
a原来是10,先使用就是赋值给b,b得到的是10,然后再+1就是a+1,所以最后a变成11了,
而b是10
相当于下面的代码
c
int a = 10;
b = a;
a = a + 1;
printf("a = %d,b = %d",a,b);
8.1.3前置--
c
int a = 10;
int b = --a;
printf("a = %d,b = %d",a,b);
使用口诀:先-1,后使用
a原来是10,先-1,后a变成9,再使用就是赋值给b,b得到的也是9,所以最后a,b都变成9了
相当于下面的代码
c
int a = 10;
a = a - 1;
b = a;
printf("a = %d,b = %d",a,b);
8.1.4后置--
c
int a = 10;
int b = a--;
printf("a = %d,b = %d",a,b);
使用口诀:先使用,后-1
a原来是10,先使用就是赋值给b,b得到的是10,然后再-1就是a-1,所以最后a变成9了,
而b是10
相当于下面的代码
c
int a = 10;
b = a;
a = a - 1;
printf("a = %d,b = %d",a,b);
8.2+
和-
这里的+
是正号,-
是负号,都是单目操作符。
运算符+
对正负值没有影响,是一个完全可以省略的运算符,但是写了也不会报错。
c
int a = +10;
int a = 10;
上面的两个a是等价的;
运算符-
用来改变一个值的正负号,负数的前面加上-
就会得到正数,正数的前面加上-
会得到负数。
c
int a = 10;
int b = -a;
int c = -10;
printf("b = %d c = %d\n",b,c);
int a = -10;
int b = -a;
printf("b = %d",b);
8.3!
该操作符是逻辑非,
例: while(!0)
九、关系操作符
c语言用于比较的表达式,称为"关系表达式"(relational expression),里面使用的运算符就成为"关系运算符"(relational expression),主要有下面6个。
>
大于运算符<
小于运算符>=
大于等于运算符<=
小于等于运算符==
相等运算符!=
不相等运算符
下面举一些例子
c
a == b;
a != b;
a < b;
a > b;
a <= b;
a >= b;
关系表达式通常返回0
或1
,表示真假。
C语言中,0
表示假,所有非零值表示真。比如,20 > 12
返回1
,12>20
返回0
。
关系表达式常用于if
或while
结构。
c
if(x == 3)
{
printf("x is 3.\n");
}
注意:相等运算符==
与赋值运算符=
是两个不一样的运算符,不要混淆。有时候,可能不小心写出下面的代码,它可以运行,但很容易出现意料之外的结果。
c
if( x = 3);
上面示例中,原意是x == 3
,但是不小心写成 x = 3
,这个式子表示对变量x
赋值3
,它的返回值为3
,所以if
判断总是为真。为了防止出现这种错误,有的程序员喜欢将变量写在等号的右边。
c
if(3 == x);
这样的话,如果把==
误写成=
,编译器就会报错。
c
if(3 = x)
另一个需要避免的错误是:多个关系运算符不宜连用。
c
i<j<k
上面示例中,连续使用两个小于运算符。这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量的值在i
和k
之间。因为关系运算符是从左到右计算,所以实际执行的是下面的表达式。
c
(i < j) < K;
上面式子中i < j
返回0
或1
,所以最终是0
或1
与变量k
进行比较。如果想要判断变量j
的值是否在i
和k
之间,应该使用下面的写法。
c
i < j && j < k;
十、条件操作符
条件操作符也叫三目操作符,需要接受三个操作数的,形式如下:
c
exp1 ? exp2 : exp3;
条件操作符的计算逻辑是:如果exp1
为真,exp2
计算,计算的结果是整个表达式的结果,如果exp1
为假,exp3
计算,计算的结果是整个表达式的结果。
十一、逻辑操作符
逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个运算符。
!
:逻辑取反运算符(改变单个表达式的真假)&&
:与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)||
:或运算符,就是或者的意思(两侧至少有一个真,则为真,否则为假)
注:C语言中,非0为真,0为假
11.1逻辑取反运算符!

11.2逻辑与运算符&&
&&
就是与运算符,也是并且的意思,&&
是一个双目操作符,使用的方式是a&&b
,&&
两边的表达式都是真的时候,整个表达式才为真,只要有一个是假,则整个表达式为假。
11.3逻辑或运算符||
||
就是或运算符,也是一个双目操作符,使用方式是a||b
,||
两边的表达式只要有一个是真的,整个表达式就是真,两边的表达式都为假的时候,才为假。
十二、逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
c
int main(){
int a = 1;
int b = 2;
int c = (a>b,a=b+10,a,b=a+1);
printf("%d\n",c);
return 0;
}
十三、下表访问[],函数调用()
13.1[]
操作数:一个数组名+一个索引值(下标)
c
int arr[10];
arr[9] = 10;
[]的两个操作数是arr和9。
13.2()
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
十四、结构体成员访问操作符
14.1结构体
C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,假设我想描述学生,描述一本书,这时单一的内置类型是不行的。描述一个学生需要名字、年龄、学号、身高、体重等;描述一本书需要作者、出版社、定价等。C语言为了解决这个问题,增强了结构体这种自定义的数据类型,让程序员可以自己创造适合的类型。
结构是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量,如:标量、数组、指针,甚至是其他结构体。
14.1.1结构的声明
c
struct tag
{
member-list;
}variable-list;
14.2结构体访问操作符
14.2.1 结构体成员的直接访问.
结构体成员的直接访问是通过点操作符.
访问的。点操作符接受两个操作数。
c
struct Point
{
int x;
int y;
} p = {1,2};
int main()
{
printf("x:%d\n,y:%d\n",p.x,p.y);
return 0;
}
14.2.2 结构体成员的间接访问 ->
结构体成员的间接访问通过箭头操作符 ->
实现,主要用于结构体指针 访问成员。其语法为 结构体指针->成员名
,本质上是 (*结构体指针).成员名
的简化写法。
c
struct Point
{
int x;
int y;
};
int main()
{
struct Point p = {3, 4};
struct Point *ptr = &p; // 定义结构体指针并指向变量p
// 通过箭头操作符修改成员
ptr->x = 10; // 等价于 (*ptr).x = 10
ptr->y = 20; // 等价于 (*ptr).y = 20
printf("x: %d\n", ptr->x); // 输出x: 10
printf("y: %d\n", ptr->y); // 输出y: 20
return 0;
}
十五、操作符的属性:优先级与结合性
15.1 优先级
操作符优先级决定表达式中运算的执行顺序。优先级高的操作符先于优先级低的操作符进行计算。常见优先级等级如下(从高到低):
-
括号与成员访问
()
函数调用、[]
数组下标、.
结构体成员、->
指针成员访问cstruct Point p = {3,4}; int val = (p.x + 5) * 2; // 括号优先计算
-
单目操作符
++
--
(前缀)、!
逻辑非、~
按位取反、*
解引用、&
取地址cint a = 10; int *ptr = &a; *ptr += 5; // 先解引用再赋值
-
乘除取模
*
乘法、/
除法、%
取模cint result = 5 + 3 * 2; // 3*2先计算,结果为11
-
加减与位移
+
-
(二元)、<<
左移、>>
右移cint val = 10 << 2 + 1; // 先计算2+1,再左移3位(10<<3=80)
-
关系与位运算
<
>
比较、&
按位与、^
按位异或、|
按位或 -
逻辑运算符
&&
逻辑与、||
逻辑或 -
赋值操作符
=
+=
-=
等复合赋值符(优先级最低)
15.2 结合性
当多个同级操作符相邻时,结合性决定运算方向。主要分为两类:
-
左结合(从左到右计算)
- 算术运算符:
+
-
*
/
- 关系运算符:
<
>
==
等
cint a = 5 * 3 / 2; // 先计算5*3=15,再15/2=7(整数除法)
- 算术运算符:
-
右结合(从右到左计算)
- 赋值操作符:
=
+=
等 - 单目运算符:
++
--
(后缀)
cint a, b; a = b = 10; // 先b=10,再a=b
- 赋值操作符:
优先级与结合性冲突案例:
c
struct Stu *p = &s;
(*p).age = 20; // 必须加括号:*的优先级低于.
此处若写成*p.age
会被解析为*(p.age)
导致错误。
十六、表达式求值
16.1 求值规则
表达式求值受三个因素影响:
-
操作符优先级
cint x = 5 + 3 * 2; // 3*2先计算,结果为11
-
操作符结合性
cint y = 10 - 5 - 3; // 左结合:10-5=5,再5-3=2
-
求值顺序的不确定性
某些情况下,操作数的求值顺序未定义(如函数参数):
cprintf("%d %d", ++i, i++); // 结果可能因编译器而异
16.2 短路求值特性
逻辑运算符&&
和||
具有短路特性:
c
int a = 0, b = 5;
if (a != 0 && b / a > 2) { // a=0时直接跳过b/a的运算
// 避免除零错误
}
16.3 顺序点(Sequence Point)
顺序点是程序中确保副作用(如变量修改)已完成执行的节点:
- 分号
;
- 逻辑运算符
&&
||
- 逗号操作符
,
- 函数调用(参数计算完成后)
c
int i = 0;
int j = i++ + i++; // 未定义行为:两个i++之间无顺序点
16.4 表达式求值注意事项
-
避免复杂表达式
拆分多步骤运算以提高可读性:
c// 难读的表达式 int result = (a << 3) | (b & 0xFF) + c * 2; // 拆解后 int temp1 = a << 3; int temp2 = b & 0xFF; int result = temp1 | (temp2 + c * 2);
-
显式使用括号
即使优先级明确,也可用括号增强可维护性:
cint val = (a > b) && (c != 0); // 比a > b && c !=0更清晰
-
警惕未定义行为
如修改同一变量多次的表达式:
cint i = 5; int x = i++ + i++; // 未定义行为
结语
以上为本人总结,如果有错误,请私信我,我会及时纠正。