【C语言】运算符优先级
- 每个操作符都有对应的优先级,如果两个操作符挨在一块,先执行优先级高的操作符,如果优先级相同,取决于他们的结合性。
- 每个操作符都有结合性。 操作符的结合性定义了操作符对操作数执行操作的顺序,例如:右结合性表示该操作符对其操作数从右向左执行操作。
优先级 | 运算符 | 描述 |
---|---|---|
1 | (), [] ,., -> | 括号 数组下标 成员对象 成员指针 |
2 | !, ~, ++, --, sizeof | 逻辑非, 按位取反, 递增, 递减, 大小运算符 |
3 | *, /, % | 乘法, 除法, 取模 |
4 | +, - | 加法, 减法 |
5 | <<, >> | 左移, 右移 |
6 | <, <=, >, >= | 小于, 小于等于, 大于, 大于等于 |
7 | ==, != | 等于, 不等于 |
8 | & | 按位与 |
9 | ^ | 按位异或 |
10 | | | 按位或 |
11 | && | 逻辑与 |
12 | || | 逻辑或 |
13 | ?: (三目运算符) | 条件运算符 |
14 | =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>= | 赋值, 复合赋值运算符 |
15 | , | 逗号运算符 |
注意事项
这里说一些需要注意的事项。
复合运算符
复合运算符有:+=、-=、*=、/=、%=、>>=、<<=、&=、|=、^=
int a = 0;
int b = 8;
a+=b; //相当于a = a+b 所有a=8
a-=b; //相当于a = a-b 因为a=8,a-b为0
//其他运算符同理,这种复合运算符可以使代码更加简洁
单目运算符
! (逻辑反操作)
- (负值)
+ (正值)
& (取地址)
sizeof (操作数的类型长度(以byte为单位))
~ (对数值的二进制位取反)
- (前置后置--)
++ (前置后置++)
* (解引用操作符)
(类型) —强制类型转换
sizeof
#include <stdio.h>
int main()
{
int a = -10;
int *p = NULL;
printf("%d\n", !2); //逻辑反操作,逻辑上一个值不是真就是假,非0即为真,!就是对一个数进行反操作2是真,!2即为假就是0
printf("%d\n", !0); //0是假,!0为真,就是1
a = -a; //原来的a为-10,-a就是10
p = &a; //&就是取a的地址
printf("%d\n", sizeof(a)); //a的长度就是int类型的长度为4byte
printf("%d\n", sizeof(int)); //int的长度为4byte
printf("%d\n", sizeof a);//这样写行不行? //正确,sizeof后面跟变量可以不写括号
printf("%d\n", sizeof int);//这样写行不行? //错误,sizeof后面跟数据类型必须加括号
return 0;
}
a++和++a
//++和--运算符
//前置++和--
#include <stdio.h>
int main()
{
int a = 10;
int x = ++a;
//先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
int y = --a;
//先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
return 0;
}
//后置++和--
#include <stdio.h>
int main()
{
int a = 10;
int x = a++;
//先对a先使用,再增加,这样x的值是10;之后a变成11;
int y = a--;
//先对a先使用,再自减,这样y的值是11;之后a变成10;
return 0;
}
#include <stdio.h>
int main()
{
int a = 1;
int b = 3;
int c = (++a, ++b, a + b);//这两种c是一样的值
int c = (a++, b++, a + b);//这两种c是一样的值
printf("%d\n",c);
return 0;
}
在复杂表达式中的区别
在更复杂的表达式中,这两种递增方式的选择可能会影响程序的逻辑和结果。
示例1:比较运算符中的使用
int a = 3;
if (a++ < 4) {
printf("True\n"); // 因为 a 先比较后递增,所以输出 True
}
// a 现在是 4
示例2:逻辑运算符中的使用
int a = 3;
if (++a < 5 && a < 4) {
printf("True\n"); // 不会执行,因为 ++a 使 a 变为 4,然后 a < 4 为假
} else {
printf("False\n"); // 输出 False
}
// a 现在是 4
示例3:循环中的使用
int a = 0;
while (++a < 5) {
printf("%d ", a); // 输出 1 2 3 4,因为循环开始时 a 先递增
}
示例4:函数参数中的使用
void increment(int x) {
x++; // 这里的递增只影响函数内部的 x
}
int main() {
int a = 5;
increment(a);
printf("%d\n", a); // 输出 5,因为函数内的递增不影响 main 函数中的 a
return 0;
}
总结
- 后置递增(
a++
)在表达式中使用时,先使用当前值,后递增。 - 前置递增(
++a
)在表达式中使用时,先递增,后使用新值。 - 在编写代码时,选择哪种递增方式取决于你希望在递增操作之前还是之后使用变量的值。
指针解引用
#include <stdio.h>
int main()
{
a = 10;
int* b = &a;
printf("%d",b); //在c语言中我们常常会用到指针,如果不对其进行解引用,那么输出的值是a的地址。
printf("%d",*b); //解引用后值为10
}
强制转换
int main()
{
float a = 10.3;
printf("%d",(int)a); //在实际中如果某个数我们定义成一个类型,但是输出时又想用另一个类型输出,那么我们就可以对其进行强制类型转换,使其强转为你想要的值,但谨慎使用!!!容易出错!!!
}
sizeof与数组形参
#include <stdio.h>
void test1(int arr[])
{
//这里arr被形参接手之后已经是首地址了,所以sizeof(arr)为8(在64位环境下,32位环境为4)
printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
//同上,ch接受过来已经是首地址了,所以地址的大小为8(64位环境下,32位环境为4)
printf("%d\n", sizeof(ch));
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr)); //整个数组的大小为40
printf("%d\n", sizeof(ch)); //整个数组的大小为10
test1(arr);
test2(ch);
return 0;
}
逻辑操作符
&&(逻辑与) ||(逻辑或)
- 不要混淆逻辑操作符和位操作符,两者之间有很大区别,一个是对二进制位进行与操作,一个是对数值进行与操作
a | b | a&b | a|b | a^b |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
int main()
{
printf("%d",1&2); //0,对二进制进行与操作,对应的二进制位都为真,结果为真
printf("%d",1&&2); //1,对数值进行与操作,都为真,结果为真
printf("%d",1|2); //3,对二进制位进行或操作,对应的二进制位只要有一个为真,结果为真
printf("%d",1||2); //1,对数值进行或操作,只要有一方为真,结果为真
}
三目运算符
exp1 ? exp2 : exp3
- 表达式1结果为真,返回表达式2,表达式1为假,返回表达式3
int main
{
if(a>10)
b = 5;
else
b = -1;
//等价于
a>10 ? b=5 : b=-1;
}
逗号表达式
(exp1, exp2, exp3, …expN)
- 逗号表达式只不过就是用逗号隔开的表达式,从左到右,依次执行,整个表达式的结果为最后一个表达式的结果,注意一定要用括号阔气老。
int main()
{
int a = 1;
int b = 3;
int c = (a++,b++,a+b);
printf("%d",c);
//c = 6 ,从左到右执行返回最右面的表达式
//等价于
//a++;
//b++;
//int c = a+b;
}
指针访问结构体
struct Stu
{
char name[10];
int age;
};
void set_age1(struct Stu stu)
{
stu.age = 18;
}
void set_age2(struct Stu* pStu)
{
pStu->age = 18; //结构成员访问
}
int main()
{
struct Stu stu;
struct Stu* pStu = &stu; //结构成员访问
stu.age = 20; //结构成员访问
set_age1(stu);
pStu->age = 20; //结构成员访问
set_age2(pStu);
return 0;
}