1.操作符分类
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
2.算数操作符
“ + ” “ - ” “ * ” “ / ” “ % ”
加 减 乘 整除 取余
/与%
![image-20230413224800173](ArithmeticOperator.assets/image-20230413224800173.png)
#include<stdio.h>
int main()
{
//除法
// “/”一般是整除
//整数类型的除法
int a = 1 / 2;
printf("%d\n", a); //--> 0
//浮点类型的除法
double b = 1.0 / 2;
printf("%f\n", b); // -- > 0.500000
double c = 1 / 2.0;
printf("%f\n",c); // -- > 0.500000
double d = 1.0 / 2.0;
printf("%f\n",d); // -- > 0.500000
// "%" 整除后的余数
int f = 7 % 2;
//注意:“%” 取摸操作符的两端必须是整数
printf("%d\n", f); // -- > 0.500000
return 0;
}
算数操作符优先级
#include<stdio.h>
//运算符优先级
int main()
{
int x = 2;
int y = 3;
int z = 8;
int sult_1;
int sult_2;
// % 取余数
sult_1 = z % x + 3;
//(8%2)+3=3
sult_2 = x + 6 % 1;
//2+(6%1)=2
printf("%d\n", sult_1); // -- > 3
printf("%d\n", sult_2); // -- > 2
}
C语言运算符优先级
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-luQyKYBh-1682495789636)(ArithmeticOperator.assets/image-20230413223048465.png)]
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|---|
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | – |
() | 圆括号 | (表达式)/函数名(形参表) | – | ||
. | 成员选择(对象) | 对象.成员名 | – | ||
-> | 成员选择(指针) | 对象指针->成员名 | – | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
~ | 按位取反运算符 | ~表达式 | |||
++ | 自增运算符 | ++变量名/变量名++ | |||
– | 自减运算符 | –变量名/变量名– | |||
* | 取值运算符 | *指针变量 | |||
& | 取地址运算符 | &变量名 | |||
! | 逻辑非运算符 | !表达式 | |||
(类型) | 强制类型转换 | (数据类型)表达式 | – | ||
sizeof | 长度运算符 | sizeof(表达式) | – | ||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | |||
% | 余数(取模) | 整型表达式%整型表达式 | |||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | |||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | |||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | |||
< | 小于 | 表达式<表达式 | |||
<= | 小于等于 | 表达式<=表达式 | |||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | |||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1?表达式2: 表达式3 | 右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | – |
/= | 除后赋值 | 变量/=表达式 | – | ||
*= | 乘后赋值 | 变量*=表达式 | – | ||
%= | 取模后赋值 | 变量%=表达式 | – | ||
+= | 加后赋值 | 变量+=表达式 | – | ||
-= | 减后赋值 | 变量-=表达式 | – | ||
<<= | 左移后赋值 | 变量<<=表达式 | – | ||
>>= | 右移后赋值 | 变量>>=表达式 | – | ||
&= | 按位与后赋值 | 变量&=表达式 | – | ||
^= | 按位异或后赋值 | 变量^=表达式 | – | ||
|= | 按位或后赋值 | 变量|=表达式 | – | ||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 | – |
3.移位操作符(不支持浮点数)
整数二进制说明
整数的二进制表示有三种:原码,反码,补码
整数在内存中存的就是补码
正整数的原码,反码,补码都相同
负整数的原码,反码,补码不相同(都是要计算的)
整型占四个字节(32个比特位)
一个字节=8个比特位
32位 整数,
正数,高位(第一位)是0
负数,高位(第一位)是1
“<<” 左移操作符
7(例)
原,反,补码表示
00000000000000000000000000000111 ---- 原码
00000000000000000000000000000111 ---- 反码
00000000000000000000000000000111 ---- 补码
代码演示
#include<stdio.h>
//正整数左移操作符
int main()
{
int a = 7;
//左移操作符
//移动的是二进制位(整数的二进制补码)
//整个二进制向左移,左边超出的丢弃,右边缺位的补0
int b = a << 1; //向左移动一位
int c = a << 2; //向左移动两位
printf("a= %d\n", a);// -- > a= 7
printf("b= %d\n", b);// -- > b= 14
printf("c= %d\n", c);// -- > c= 28
return 0;
}
注意:这里移动的是整数的补码,需要将原码转换为补码,再对补码移位,然后在将补码转换为原码,再进行printf
解释
![image-20230415220317780](ArithmeticOperator.assets/image-20230415220317780.png)
-7(例)
原,反,补码表示
因为-7是负数,所以二进制表示第一位为1(第一位又叫高位,符号位)
10000000000000000000000000000111 ----- 原码
11111111111111111111111111111000 ---- 反码
11111111111111111111111111111001 ---- 补码
负数原反补变化规则
(负数)原码变反码:原码符号位不变,其他位按位取反就是反码(按位取反:0变1,1变0)
(负数)反码变补码:反码+1就是补码(001+1=010)
代码演示
//左移操作符(负整数)
int main()
{
int a = -7;
//左移操作符
//移动的是二进制位(整数的二进制补码)
//整个二进制向左移,左边超出的丢弃,右边缺位的补0
int b = a << 1;
int c = a << 2;
printf("a= %d\n", a);// -- > a= -7
printf("b= %d\n", b);// -- > b= -14
printf("c= %d\n", c);// -- > c= -28
return 0;
}
注意:这里移动的是整数的补码,需要将原码转换为补码,再对补码移位,然后在将补码转换为原码,再进行printf
解释
![image-20230415221712459](ArithmeticOperator.assets/image-20230415221712459.png)
结论 "<<"有乘2的效果
“>>” 右移操作符
移位(算数与逻辑)
算数移位:右边丢弃,左边补原符号位
逻辑移位:右边丢弃,左边补0
PS:正数无差别,负数大多数编译器用逻辑移位
7(例)
原,反,补码表示
00000000000000000000000000000111 ---- 原码
00000000000000000000000000000111 ---- 反码
00000000000000000000000000000111 ---- 补码
代码
//右移操作符(正整数)
//移动的是二进制补码
//输出二进制原码
int main()
{
int a = 7;
int b = a >> 1;
int c = a >> 2;
printf("a= %d\n", a);// -- > a= 7
printf("b= %d\n", b);// -- > b= 3
printf("c= %d\n", c);// -- > c= 1
return 0;
}
解释
![image-20230417201317108](ArithmeticOperator.assets/image-20230417201317108.png)
-7(例)
原,反,补码表示
因为-7是负数,所以二进制表示第一位为1(第一位又叫高位,符号位)
10000000000000000000000000000111 ----- 原码
11111111111111111111111111111000 ---- 反码
11111111111111111111111111111001 ---- 补码
移位(算数与逻辑)
算数移位:右边丢弃,左边补原符号位
逻辑移位:右边丢弃,左边补0
PS:正数无差别,负数大多数编译器用逻辑移位(因此咱们自己默认是逻辑移位,算数移位了解即可)
代码
//右移操作符(负数)
//移动的是二进制补码
//输出二进制原码
//逻辑移位
int main()
{
int a = -7;
int b = a >> 1;
int c = a >> 2;
printf("a= %d\n", a);// -- > a= -7
printf("b= %d\n", b);// -- > b= -4
printf("c= %d\n", c);// -- > c= -2
return 0;
}
解释
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qSvtZaYf-1682495789639)(ArithmeticOperator.assets/image-20230417203403168.png)]
4.位操作符(不支持浮点数)
概述
“&” – > 按 (2进制) 位 与 1 1 得 1, 1 0 得 0
“|” – > 按 (2进制) 位 或 0 0 得 0, 1 0 得 1
“^” – > 按 (2进制) 位 异或 A A 得 0, A B 得 1
“&” 与
规则
二进制:1 1=1, 1 0=0。
代码演示
int main()
{
int a = 3;
int b = -5;
int c = a & b;
//00000000000000000000000000000011 -- 3的补码
//10000000000000000000000000000101 -- -5的原码
//11111111111111111111111111111010 -- -5的反码
//11111111111111111111111111111011 -- -5的补码
//对比两者的补码:1 1得1, 1 0得0。
//00000000000000000000000000000011 -- 3的补码
//11111111111111111111111111111011 -- -5的补码
//结果 00000000000000000000000000000011 -- 该补码等于3
//正整数原码等于补码,所以输出00000000000000000000000000000011的10进制:3
printf("c= %d\n", c);// -- > c= 3
return 0;
}
“|” 或
规则
二进制:0 0=0, 1 0=1。
代码演示
//"|" -- > 按(2进制) 位 或
int main()
{
int a = 3;
int b = -5;
int c = a | b;
//00000000000000000000000000000011 -- 3的补码
//10000000000000000000000000000101 -- -5的原码
//11111111111111111111111111111010 -- -5的反码
//11111111111111111111111111111011 -- -5的补码
//对比两者的补码:0 0得0, 1 0得1。
//00000000000000000000000000000011 -- 3的补码
//11111111111111111111111111111011 -- -5的补码
// 结果11111111111111111111111111111011 -- 补码 为负,应转为原码
//11111111111111111111111111111010 -- 反码
//10000000000000000000000000000101 -- 原码 -5
//输出10进制:-5
printf("c= %d\n", c);// -- > c= -5
return 0;
}
“^” 异或
规则
二进制补码:a a得0 a b得1
整数:a^a=0 0^a=a
代码演示
//" ^ " -- > 按(2进制) 位 异或
int main()
{
int a = 3;
int b = -5;
int c = a ^ b;
//00000000000000000000000000000011 -- 3的补码
//10000000000000000000000000000101 -- -5的原码
//11111111111111111111111111111010 -- -5的反码
//11111111111111111111111111111011 -- -5的补码
//对比两者的补码:aa得0, ab得1
//00000000000000000000000000000011 -- 3的补码
//11111111111111111111111111111011 -- -5的补码
//结果 11111111111111111111111111111000 -- 补码 为负,应转为原码
//11111111111111111111111111110111 -- 反码
//10000000000000000000000000001000 -- 原码 -8
//输出10进制:-8
printf("c= %d\n", c);// -- > c= -8
return 0;
}
题目
实现两个整数交换
1,创建一个临时变量(主要使用本方法)
//两个整数的交换(创建一个老师变量)
//两杯水三个杯子
int main()
{
int a = 3;
int b = 5;
int c = 0;//临时变量
printf("a= %d\n", a);// -- > a= 3
printf("b= %d\n", b);// -- > b= 5
printf("------------\n");
c = a;
a = b;
b = c;
printf("a= %d\n",a);// -- > a= 5
printf("b= %d\n",b);// -- > b= 3
return 0;
}
2,使用 “^” 异或*(不创建临时变量,了解即可)
交换律
3^3=0 --> a^a=0
011 3
011 3
000 0
0^5=5 --> 0^a=a
000 0
101 5
101 5
3^3^5=5
3^5^3=5
异或操作符支持交换律
011 3
101 5
110 6
011 3
101 5
代码
两个整数的交换(使用 "^" 异或 操作符)
//0 ^ a = a
//a ^ a = 0
int main()
{
int a = 3;
int b = 5;
printf("a= %d\n", a);// -- > a= 3
printf("b= %d\n", b);// -- > b= 5
printf("------------\n");
a = a ^ b;//a=3^5
b = a ^ b;//(3^5)^5 == 3^5^5 == (5^5)^3=3 -- > b= 3
a = a ^ b;//(3^5)^3 == 3^5^3 == (3^3)^5=5 -- > a= 5
printf("a= %d\n",a);// -- > a= 5
printf("b= %d\n",b);// -- > b= 3
return 0;
}
5 赋值操作符
赋值操作符 =
复合赋值符
+=
-=
……
int main()
{
int a = 3;//赋值操作符
a = a + 5;
a += 5;//复合赋值操作符
a = a >> 1;
a >>= 1;//复合赋值操作符
return 0;
}
6.单目操作符
概述
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
! 逻辑反操作符
//! 逻辑反操作符
int main()
{
int flag = 3;
//flag为真,进入if
if(flag)
{ }
//flag为假,进入if
if(!flag)
{ }
return 0;
}
//c语音中,0不是假,非0表示真
“-“与”+”
//"-" 单目操作符
//"+"作单目操作符时写没写都一样
int main()
{
int a = -10;
int b = +a;
int c = -a;
printf("a= %d\n", a);// -- > a= -10
printf("b= %d\n", b);// -- > b= -10
printf("c= %d\n", c);// -- > c= 10
return 0;
}
& 取地址
//& 取出变量在内存中得起始地址
// a占四个字节,每个字节都有内存地址。
//取出占的四个字节中 第一个字节所占的内存地址(起始地址)
int main()
{
int a = 10;
printf("%p\n", a);// 000000000000000A
int* p = &a;//p就是指针变量
return 0;
}
sizeof 操作数的类长度(以字节为单位)
计算变量 类型 数组 所占空间的大小
//sizeof 操作符 单位:字节(byte)
//计算的是变量所占空间的大小,字节(byte)
//计算类型所创建的变量占据空间的大小,字节(byte)
int main()
{
//变量
int a = 10;
//计算的是a所占内存的大小,单位是字节
int aa = sizeof(a);
printf("a所占内存的大小:%d\n", aa);// --> a所占内存的大小:4
//类型
//计算int类型所占空间的大小
int n = sizeof(int);
printf("int类型所占空间的大小:%d\n", n);// --> int类型所占空间的大小:4
//数组
//计算整个arr数组所占空间的大小
int arr[5] = { 0 };
printf("整个arr数组所占空间的大小:%d\n", sizeof(arr));// --> 整个arr数组所占空间的大小:20
return 0;
}
~ 对一个数的二进制按位取反
基本
//~ 按二进制按位取反
int main()
{
int a = 0;
// 00000000000000000000000000000000 --> 0的补码
// 11111111111111111111111111111111 --> ~a
// 11111111111111111111111111111110 --> `a的反码
// 10000000000000000000000000000001 --> ~a的原码 == -1
printf("~0 == %d\n", ~a);// --> ~0 == -1
int b = 3;
//00000000000000000000000000000011 --> 3的补码
//11111111111111111111111111111100 --> ~3(补码)
//11111111111111111111111111111011 --> ~3(反码)
//10000000000000000000000000000100 --> ~3 (原码) == -4
printf("~3 == %d\n", ~b);// --> ~3 == -4
return 0;
}
扩展
0改1 (正数 补码)
//修改 正数 指定补码位置的数(0改1)
int main()
{
int a = 13;
int b = 1 << 4;
// "|"或 二进制:0 0=0, 1 0=1。
a |= (1 << 4);
// 00000000000000000000000000001101 //a = 13;
// 00000000000000000000000000010000 //b = 1 << 4;
// 00000000000000000000000000011101 //补码 -- 29(正数三码相同)
printf("%d\n", a);//29
printf("%d\n", b);//16
return 0;
}
1改0 (正数 补码)
//修改 正数 指定补码位置的数(1改0)
int main()
{
int a = 29;
// ~ 按二进制按位取反
// "&" 与 二进制:1 1=1, 1 0=0。
a &= (~(1 << 4));
// 00000000000000000000000000010000 //1 << 4 == 16
// 11111111111111111111111111101111 // ~( 1 << 4 )
// 11111111111111111111111111101111 // ~( 1 << 4 )
// 00000000000000000000000000011101 //29
// 00000000000000000000000000001101 //13
printf("%d\n", a);//13
return 0;
}
++前后置(–同理)
主要
//++前后置
int main()
{
//后置++
int a = 3;
int b = a++;
printf("%d\n", a);// --> 4
printf("%d\n", b);// --> 3
//前置++
int c = 3;
int d = ++c;
printf("%d\n", c);// --> 4
printf("%d\n", d);// --> 4
//注意,表达式输出
int z = 10;
printf("%d\n", z++);// --> 10
printf("%d\n", z);// --> 11
return 0;
}
注意
int main()
{
//注意,前后位置不同,输出结果也不同(函数调用等情况也同理)
int z = 10;
printf("%d\n", z++);// --> 10(先输出,后++)
printf("%d\n", z);// --> 11
printf("%d\n", ++z);// --> 12(先++,后输出)
printf("%d\n", z);// --> 12
return 0;
}
单目操作符与双目操作符
单目操作符:只有一个操作数
双目操作符:有两个操作数
以下为例
例 “-”即是双目操作符也是单目操作符
当 a-b, "-"是双目操作符("-"有两个操作数)
当 -b,”-“表示b为负数,此时"-"为单目操作符("-"只有一个操作数)