Files
BlogPosts/Collection/YoudaoyunNotes/02C语言/04-运算符.md

328 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

- 概述运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 语言内置了丰富的运算符,并提供了以下类型的运算符:
- 算术运算符:+、-、*、/、%、++、--
- 关系运算符:>、<、>=、<=、==、!=
- 逻辑运算符:&&、||、!
- 位运算符:&、|、~、<<、>>、^
- 赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
- 杂项运算符:&、*、sizeof、?:、return、,
注意:
运算符可根据操作数的个数进行分类,有单目(一元)、双目(二元)、三目(三元)
| 操作数数量 | 运算符类型 | 具体运算符 |
| -- | -- | -- |
| 单目 | 自增 / 自减 | ++ |
| 正负号 | + |
| 逻辑非 | ! |
| 按位取反 | ~ |
| 地址与解引用 | & |
| 类型转换 | (类型) |
| 长度计算 | sizeof |
| 指针成员访问 | -> |
| 双目 | 算术运算 | + |
| 关系运算 | == |
| 逻辑运算 | && |
| 按位运算 | & |
| 赋值运算 | = |
| 逗号运算 | , |
| 三目 | 条件运算 | ? : |
# 一、算术运算符
![](images/WEBRESOURCE2fdad5c1e645e6811dfb870a3d8b4c56image.png)
- 注意:
- C 语言中很多关键字在不同的场合具有不同的意思, 比如”+”和”-”, 如果它们只有一个操作数, 则分别是取正和取负运算, 比如+10 -a 等, 如果它们左右两边有两个操作数, 则分别为加法和减法, 如 a-3。 再如星号”*”, 其出现在定义语句时为指针标记, 只有一个操作数时为解引用运算符, 有两个操作数时为乘法运算, 而与正斜杠”/”一起使用时又表示注释符。 由此可见, 同样的运算符在不同的场合有不同的意思。
- 两个整型相除的结果是整型, 小数部分将被舍弃(而不是四舍五入) 比如 17/10的结果是 1。
- 取模运算符左右两边的操作数都必须是整型(不仅是整数, 比如 3.0 在数学意义上是整数, 但在计算机中它是一个浮点型数而不是整型数, 这样的数据是不能作为取模运算的操作数的)
## 练习
从键盘输入一个三位数,在分别打印出它的个位十位和百位
拓展:任意位数,打印每一位
- ++:自增 --:自减
- 自增自减运算符使操作数加 1 或者减 1 当其作为前缀(如++a 时先进行自增自减再参与运算, 当其作为后缀(如 a++ 时先参与运算再进行自增自减。
```c
int a=10;
printf("a=%d\n", a++); // 后缀先用后加 10
printf("a=%d\n", a);   // 11
int b=10;
printf("b=%d\n", ++b); // 前缀先加后用 11
```
> int a=5,b=4;
> int c=a+++b; // a++ +b(√) a+ ++b a:6 b:4 c:9
> int d=a+++++b;// a++ ++ +b //编译报错 a:7 b:5 c:9 d:10 int d=a+++(++b);// a:7 b:5 c:9 d:11
> 问a,b,c,d的值分别是多少
# 二、关系运算符
![](images/WEBRESOURCE059f0c15158165303fc0fc990a90a445image.png)
- 注意:关系运算符的结果为真(1)或假(0),判断等于运算符是==,而=是赋值运算符若if(x==1)写为了if(x=1)编译时不报错,但判断表达式变成了赋值表达式,其结果取决于赋值的值是真(非0)还是假(0)为了避免这样的问题发生则建议在书写判断表达式时将常量放在左边如if(1==x)如果写成了if(1=x)则编译时会报错。
- 不等于运算符可以省略的情况
- int a; if(a) ==> if(a!=0)
- char a; if(a) ==> if(a!='\0')
- `int *a; if(a) ==> if(a!=NULL)`
- bool a; if(a) ==> if(a!=false)
```c
void send_string(char *msg)
{
while(msg && *msg) // msg!=NULL *msg!='\0'
{
msg++;
}
}
```
# 三、逻辑运算符
- 数学上的布尔代数, 可以用 C 语言中的逻辑运算符来表达, 也可以用位运算符来表达。当逻辑运算的操作数是表达式时用前者, 当操作数是位时用后者。
![](images/WEBRESOURCE167c2f360443ad063a8c62e5be84ad85image.png)
- 逻辑运算符的结果为逻辑真(1)或逻辑假(0),逻辑反运算符是单目运算符, 也就是说它只有一个目标操作数;逻辑与和逻辑或是双目运算符,它们对左右两边的表达式进行与操作和或操作
![](images/WEBRESOURCEba4b56e9d9f7a758da348629635d6cf6image.png)
逻辑与&&:将两个表达式串联起来,当且仅当左右两个表达式都为真时结果为真,否则为假。
逻辑或||:将两个表达式并联起来,当且仅当左右两个表达式都为假时结果为假,否则为真。
在条件表达式中若逻辑与&&左值为假右值将不进行判定,逻辑或||左值为真右值将不进行判定
## 练习
从键盘输入三个数,判断能否构成三角形
# 作业1
1. 编写程序实现从键盘输入年月日,输出该日期时该年的第几天。
1. 中国古代数学家张丘建在他的《算经》中提出了一个著名的“百钱买百鸡问题”,鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问翁、母、雏各几何?
1. 有3对情侣参加婚礼3个新郎为A、B、C3个新娘为X、Y、Z有人想知道究竟谁与谁结婚于是就问新人中的三位得到如下结果A说他将和X结婚X说她的未婚夫是CC说他将和Z结婚。这人事后知道他们在开玩笑说的全是假话。那么究竟谁与谁结婚呢
> 建立world文档注明题目编号将源代码及运行结果截图写入文档以自己的名字命名提交到飞秋
# 四、位运算符
![](images/WEBRESOURCEea237a3e83f613d86fdfed8580c001c5image.png)
- 以二进制的bit(位)进行运算,逐位进行运算
- 运算规则:
- 按位与&有0为0全1为1 如1001 & 0110 ==> 0000
- 按位或|有1为1全0为0 如1001 | 0110 ==> 1111
- 按位取反~,单目逐位取反 如:~1010 ==> 0101
- 按位异或^相同为0不同为1 如1011 ^ 0110 ==> 1101
```c
1011 ^ 0110 ==> 1101
1011 ^ 1101 ==> 0110
0110 ^ 1101 ==> 1011
// 常用于在不使用额外内存的情况下实现两数交换
a = a ^ b;
b = a ^ b;
a = a ^ b;
```
- 按位左移<< 数据向左(高位)移动,右(低位)补0移出范围直接丢弃
- 按位右移>> 数据向右(低位)移动,左(高位)补0移出范围直接丢弃
![](images/WEBRESOURCEf043bb345ce02a43791f1afe7466e30dimage.png)
## 练习
1. 假设有如下程序请问输出结果是什么?
1. 假设有一个无符号32位整型数据 unsigned int data=0x12FF0045请**编写程序**使用位运算将data的14、15位修改为1将22、23位修改为0其他位保持不变输出结果。
# 作业2
1. 写出你知道的将两数交换的所有方法
# 五、赋值运算符
| 运算符 | 描述 | 实例 |
| -- | -- | -- |
| = | 简单的赋值运算符,把右边操作数的值赋给左边操作数,左操作数不能是常量 | C = A + B 将把 A + B 的值赋给 C |
| += | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
| -= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
| *= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
| /= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
| %= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
| <<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
| >>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
| &= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
| ^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
| |= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
```c
int a = 12;
a += 13; // a = a+13; a 25
a *= 2; // a = a*2; a 50
a %= 5; // a = a%5; a 0
a += 5+2; // a = a+(5+2) a 7
a *= 5+8; // a = a*(5+8) a 91
```
# 六、杂项运算符
| 运算符 | 描述 | 实例 |
| -- | -- | -- |
| sizeof(x) | 计算x所占内存的长度单位是字节。 | int asizeof(a) 将返回 4其中 a 是整数。 |
| & | 取得变量的地址(指地址)。 | &a; 将给出变量在内存中的地址。 |
| * | 取得变量地址中的值(指针)。 | *a; a是一个地址将地址中的值取出。 |
| ? : | 条件表达式(三目运算符) | X>Y?X:Y 如果X>Y为真 ? 则值为 X : 否则值为 Y |
| return | 在函数中返回一个值给上一级函数 | |
| , | 逗号运算符 | |
- sizeof(),它不是函数,是一个运算符;
```c
int a;
// 计算a的内存大小
sizeof (a);
sizeof a; // 若sizeof后跟变量名称则括号可以省略
sizeof (int);
sizeof int; // 若sizeof后跟数据类型则括号不可以省略
```
- 在C语言中&没有左操作数时表示取址(取址符),否则表示位与。取址的作用是获取存储数据变量的地址。
```c
int a = 500;
printf("a address:%p\n", &a); // 地址采用十六进制数表示
```
- 在C语言中*没有左操作数时表示取值(解引用符),若左操作数是数据类型则表示声明定义一个指针,否则表示乘法。
```c
int a = 20;
int *p = &a; // *表示声明定义一个指针p(用于存放地址的变量)
*p = 30; // *表示解引用p指针访问p所保存的地址的值并将这个值修改为30
*p; // *表示解引用p指针,访问p所保存的地址的值
```
- return的作用是在函数中将本函数中的值(通常是执行结果),返回给调用本函数的函数。
```c
int fun(void)
{
return 886; // 将886返回个调用者
}
int main(void)
{
int a = fun(); // 调用fun函数并接收其返回值
return 0;
}
```
- 逗号运算符',',运算时从左到有,整个表达式的结果取决于最后一个表达式。
```c
int a=1,b=2;
int x = (a++,b++,a+b); // 需要使用括号包含,因为,运算符的优先级最低
// 计算顺序a++ b++ a+b的结果赋值给x ==> 5
```
## 练习
- 输入三个数,输出最小值和最大值(体验不同运算符的区别)
- 学习成绩score>=90用'A'80~89用'B', 60~79用'C,60以下用'D'表示,编写代码输入成绩输出对应的的等级
# 七、运算符优先级
| 优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 | | | | |
| ------ | -------- | -------------- | ---------- | ---- | -------- | --- | --- | --- | --- |
| 1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | -- | | | | |
| () | 圆括号 | (表达式)/函数名(形参表) | | | | | | | |
| . | 成员选择(对象) | 对象.成员名 | | | | | | | |
| -> | 成员选择(指针) | 对象指针->成员名 | | | | | | | |
| 2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 | | | | |
| ~ | 按位取反运算符 | ~表达式 | | | | | | | |
| ++ | 自增运算符 | ++变量名/变量名++ | | | | | | | |
| -- | 自减运算符 | --变量名/变量名-- | | | | | | | |
| * | 取值运算符 | *指针变量 | | | | | | | |
| & | 取地址运算符 | &变量名 | | | | | | | |
| ! | 逻辑非运算符 | !表达式 | | | | | | | |
| (类型) | 强制类型转换 | (数据类型)表达式 | -- | | | | | | |
| sizeof | 长度运算符 | sizeof(表达式) | | | | | | | |
| 3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 | | | | |
| * | 乘 | 表达式*表达式 | | | | | | | |
| % | 余数(取模) | 整型表达式%整型表达式 | | | | | | | |
| 4 | + | 加 | 表达式+表达式 | 左到右 | | | | | |
| - | 减 | 表达式-表达式 | | | | | | | |
| 5 | <<  | 左移 | 变量<<表达式 | 左到右 | | | | | |
| >>  | 右移 | 变量>>表达式 | | | | | | | |
| 6 | >  | 大于 | 表达式>表达式 | 左到右 | | | | | |
| >= | 大于等于 | 表达式>=表达式 | | | | | | | |
| <  | 小于 | 表达式<表达式 | | | | | | | |
| <= | 小于等于 | 表达式<=表达式 | | | | | | | |
| 7 | == | 等于 | 表达式==表达式 | 左到右 | | | | | |
| = | 不等于 | 表达式!= 表达式 | | | | | | | |
| 8 | & | 按位与 | 表达式&表达式 | 左到右 | | | | | |
| 9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | | | | | |
| 10 | | | 按位或 | 表达式 | 表达式 | 左到右 | | | |
| 11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | | | | | |
| 12 | | | | 逻辑或 | 表达式 | | 表达式 | 左到右 | |
| 13 | ?: | 条件运算符 | 表达式1? | 右到左 | 三目运算符 | | | | |
| 14 | = | 赋值运算符 | 变量=表达式 | 右到左 | -- | | | | |
| /= | 除后赋值 | 变量/=表达式 | | | | | | | |
| *= | 乘后赋值 | 变量*=表达式 | | | | | | | |
| %= | 取模后赋值 | 变量%=表达式 | | | | | | | |
| += | 加后赋值 | 变量+=表达式 | | | | | | | |
| -= | 减后赋值 | 变量-=表达式 | | | | | | | |
| <<= | 左移后赋值 | 变量<<=表达式 | | | | | | | |
| >>= | 右移后赋值 | 变量>>=表达式 | | | | | | | |
| &= | 按位与后赋值 | 变量&=表达式 | | | | | | | |
| ^= | 按位异或后赋值 | 变量^=表达式 | | | | | | | |
| | = | 按位或后赋值 | 变量 | =表达式 | | | | | |
| 15 | | 逗号运算符 | 表达式,表达式,… | 左到右 | 从左到右顺序运算 | | | | |
记忆办法:去掉一个最高优先级括号(),去掉两个最低优先级赋值和逗号
![](images/WEBRESOURCE024f291ce6ddbfc8e43e98913881be10image.png)
[C语言运算符优先级顺口溜](https://blog.csdn.net/wt051133/article/details/145663515)
# 练习
[运算符1.docx](attachments/WEBRESOURCEbbcc325c1c1c565fa7dbe4f13a3f2f9d运算符1.docx)
# 作业
[运算符测试.docx](attachments/WEBRESOURCE757c8acbaa371ecec8cc55fab8756448运算符测试.docx)