目录
这些是我在学习C语言操作符过程中的一些整理的学习心得,首先我将一部分操作符运算的优先级放在本文开头,后面是详解。
C语言部分运算符优先级表
优先级 | 运算符 | 名称或含义 |
1 | [ ] | 数组下标 |
() | 圆括号 | |
. | 成员选择(对象) | |
-> | 成员选择(指针) | |
2 | - | 负号运算符 |
~ | 按位取反运算符 | |
++ | 自增运算符 | |
-- | 自减运算符 | |
* | 取值运算符 | |
& | 取地址运算符 | |
! | 逻辑非运算符 | |
(类型) | 强制类型转换 | |
sizeof | 长度运算符 | |
3 | / | 除 |
* | 乘 | |
% | 余数(取模) | |
4 | + | 加 |
- | 减 | |
5 | << | 左移 |
>> | 右移 | |
6 | > | 大于 |
>= | 大于等于 | |
< | 小于 | |
<= | 小于等于 | |
7 | == | 等于 |
!= | 不等于 | |
8 | & | 按位与 |
9 | ^ | 按位异或 |
10 | | | 按位或 |
11 | && | 逻辑与 |
12 | || | 逻辑或 |
13 | ?: | 条件运算符 |
14 | = | 赋值运算符 |
/= | 除后赋值 | |
*= | 乘后赋值 | |
%= | 取模后赋值 | |
+= | 加后赋值 | |
-= | 减后赋值 | |
<<= | 左移后赋值 | |
>>= | 右移后赋值 | |
&= | 按位与后赋值 | |
^= | 按位异或后赋值 | |
|= | 按位或后赋值 | |
15 | , | 逗号运算符 |
算术运算符
+
-
*
/
%
++
--
-
注意点
-
% 取余 只适合于整数(char)
-
/ 整数不能除以0(浮点数除外)
-
++/--
-
前++/-- 在表达式先自增/减,然后参与运算
-
后++/-- 先取值进行运算,然后自增/减
-
在同一个表达式,尽量避免对同一个变量进行多次自增/自减
-
在调用函数传递参数时,避免对传递进行自增/减,特别是宏函数
-
-
关系运算符
>
>=
<
<=
==
!=
-
注意
-
关系表达式的结果为0/1
-
多个关系表达式需要用逻辑运算符连接
int a = 0; scanf("%d",&a); if(0 < a < 10){ //恒成立 (0<a) < 10 0<a的结果要么是0,要么是1 printf("a在(0,10)区间\n"); } if(0 < a && a < 10){ //判断a是否在(0,10)区间 }
-
判断相等,不要写成赋值
if(a == 10) ==> if(10 == a)
-
逻辑运算符
&&
||
!
-
数据与逻辑值
-
在逻辑领域,非"零"即真,真即"1"
int a = 10,b = 20; if(a && b){ //10 && 20 这里面的10和20逻辑真 }
-
逻辑表达式的结果是 0或者1
-
短路特性
-
0&&++i;
-
逻辑与&&运算符,&&前面表达式如果为假(0),则后半表达式不运算
-
-
1||++i;
-
逻辑或||运算符,||前面表达式如果为真(1),则后半表达式不运算
-
-
后面部分结果影响不了表达式最终的结果,短路径
-
-
逻辑&&运算符优先级 高于 逻辑||
a || b && c ===> a || (b && c) a && b || c ===> (a && b) || c
位运算符
&
|
^
~
>>
<<
-
只适用于整数
-
&|^ 相同位置的二进制位进行运算
num & -1 == num num | -1 == -1 num | 0 == num num ^ 0 == num num ^ -1 == ~num == -(num + 1) num 如果是正数 -num = ~num + 1
-
右移分情况
-
有符号的数 左边空出的位全部补符号位
-
无符号的数 左边补0
-
-
左移
-
右边空出的位补0
-
-
右移1位相当于除以2 (负奇数除外 n/2-1)
-
左移1位相当于乘以2
赋值运算符
= += -= *= /= >>= <<= &= |= ^= &&= %=
-
数据溢出
-
整数数据,宽字节整数赋值窄字节变量时,只截取低字节数据,多出部分舍弃
-
浮点数赋值整数,直接舍弃小数部分,且整数也可能溢出
-
-
数据填充
-
整数数据,窄字节数据赋值给宽字节变量时,需要在高位填充
-
窄字节数据如果是signed类型,则高位填充符号位
-
窄字节数据如果是unsigned类型,则高位填充0
-
-
三目运算符
?:
expr?res1:res2
if(expr){
return res1; //res1 可以是一个语句
}else{
return res2; //res2 可以是一个语句
}
取址/解引用运算符
& 获取变量的存储地址 虚拟内存 编号 %p 十六进制的整数
* 解引用 *(指针/内存) 取得内存地址中的数据
如果内存/指针的类型为 void * 则不能解引用
下标运算符
[]
arr[index] <==> *(arr+index)
-
本质是指针偏移解引用
-
下标运算符的操作数可以交换
arr[i] <===> i[arr]
sizeof
-
sizeof是操作符,不是函数
-
sizeof操作数可以是类型,也可以是变量,表达式,语句
-
操作数如果是类型,必须要有小括号 sizeof(类型)
-
操作数如果不是类型名,则()可省 sizeeof ret
-
-
sizeof只关心操作数的类型,不会计算结果
-
sizeof(表达式) 表达式不会运算
-
sizeof(函数(参数)) 不会调用函数,只关心函数返回值类型
-
sizeof(函数名) == 1 C语法规定,未定义的结果
-
void func(int arr[],int len){ //arr <===> int *arr
printf("%lu\n",sizeof(arr)); //4/8
}
void func1(int arr[10]){ //int arr[10] 形参列表 int *arr
printf("%lu\n",sizeof(arr)); //4/8
}
int main(){
int arr[10] = {};
printf("%lu\n",sizeof(arr)); //40
func(arr,10);
return 0;
}
sizeof("pointer"); //8 包含'\0'
char *s = "pointer";
sizeof(s); //4/8 求指针变量s的内存空间大小
sizeof("ab"); //3
char *s1 = "ab";
sizeof(s1); //4/8
char s2[] = "hello";
sizeof(s2); //6
char s3[10] = "hello";
sizeof(s3); //10
sizeof('a'); //4
char ch = 'a';
sizeof(ch); //1
-
sizeof(long) 4/8
-
sizeof(long double) 12/16
-
sizeof(指针) 4/8
成员访问/间接成员访问运算符
.
->
结构体变量.成员名
结构体指针->成员名
其它
,
()
(x,y,c,a+b,c+d,w*y) 从左往右依次计算,最终的结果取最后一个表达式的结果
运算符的优先级
-
逻辑非 > 算术运算符 > 关系运算符 > 逻辑&& > 逻辑|| > 赋值运算符
-
位运算符~ > 算术运算符 > 移位(>>/<<)
char ch = 188;
int num = ~ch >> 1 + 2;
unsigned ch1 = 188;
int num = ~ch >> 1 + 2;
数据提升
-
在混合类型运算时
-
char 会自动提升为 int类型
-
unsigned char ---> unsigned int
-
short 会自动提升为 int类型
-
-
在有符号和无符号数据进行运算符时
-
有符号 --> 无符号
-