C语言程序设计2
运算符
-
用算术运算符将运算对象(也称操作数)连接起来的,符合C语言语法规则的式子,称为算术表达式。
-
运算对象包括常量、变量、函数等
例如:a * b / c - 1.5 + ‘a’
-
C语言常用运算符
- 算术运算符(+、-、*、/、%)
- 关系运算符(>、<、==、>=、<=、!=)
- 逻辑运算符(!、&&、||)
- 位运算符(<<、>>、&、|、~、^)
- 赋值运算符(=及其扩展赋值运算符)
- 条件运算符(? :)
- 逗号运算符(,)
- 指针运算符(*和&)
- 求字节数运算符(sizeof(类型或变量))
- 强制类型转换运算符((变量或常量))
- 分量运算符(. ->)
- 下标运算符([ ])
- 其他(如函数调用运算符())
-
运算符分类(根据操作数个数分):
一元(目):+(正)、-(负)、++、–、!
二元(目):+、-、*、/、%
三元(目):条件运算符
知识点1【算术运算符】
-
注意:(+、-、*、/、%)
- % 两边的数值必为整数
- 余数的符号与% 前的数字保持一致
- *、/ 若操作数都为整数,则结果必为整数。
void test05() { printf("%d\n", 5/2); printf("%d\n", 5%2); } int main() { test05(); return 0; }
2 1
案例1
void test06() { int num = 0; //键盘输入一个int数 printf("请输入一个整型数据:"); scanf("%d", &num); //判断是否能被3整除 if(num % 3 == 0) { printf("可以被3整除。\n"); } else { printf("不能被3整除。\n"); } } int main() { test06(); return 0; }
请输入一个整型数据:15 可以被3整除。
案例2
{ printf("%d\n", 5/2);//取整 printf("%f\n",5/2.0f); } int main() { test07(); return 0; }
2 2.500000
知识点2【关系运算符】
- (>、<、==、>=、<=、!=)
知识点3【逻辑运算符】
-
(逻辑非 !、逻辑与 &&、逻辑或 ||)
-
! 取反
-
&& 二元运算符(短路特性)
规则:同真为真 一假则假
A && B(如果A为假 系统不会执行B 这就是&&的短路特性)
-
|| 二元运算符
规则:同假则假 一真则真
-
-
优先级
- ! > && > ||
void test08() { printf("%d\n", !1); printf("%d\n", !0); //C语言 规定 非0表示逻辑真 0为假 printf("%d\n", !-1); } int main() { test08(); return 0; }
0 1 0
案例1
void test09() { if((2>3) && (5>4)) { printf("ok\n"); } else { printf("no\n"); } } int main() { test09(); return 0; }
no
案例2 验证短路特性
void test10() { int num = 10; printf("比较之前num = %d\n", num); (2>3) && (num = 10); printf("比较之后num = %d\n", num); (3>2) || (num = 100);//num = 100不会执行。 printf("比较之后num = %d\n", num); } int main() { test10(); return 0; }
比较之前num = 10 比较之后num = 10 比较之后num = 10
知识点4【位运算符】二进制位操作
-
&:按位与
语法:全1为1 其他为0
位数:7654 3210 (从右向左)
1010 1010
& 1111 0000
——————
1010 0000
特点:和1相与 保持不变 和0相与 清零
应用场景:将固定为 清零
-
|:按为或
语法:有1就为1 全0才为0
1010 1010
| 1111 0000
————————
1111 1010
特点:和0相或 保持不变 和1相或 置1.
案例:将1010 1010的第2、3为置1 其他为保持不变
1010 1010
| 0000 1100
————————
1010 1110
应用场景:将固定为置1
-
~:按为取反
语法:0变1 1变0
~1010 1010 ==0101 0101
应用场景:配合&、| 操作
-
^:按位异或
语法:相同为0 不同为1
1010 1010
^ 0000 1111
————————
1010 0101
特点:和0异或 保持不变 和1异或 取反。
应用场景:将固定的为 发生高低电频 翻转。
案例:将1010 1010 的第0位 发生翻转
1010 1010
^ 0000 0001
————————
1010 1011
^ 0000 0001
————————
1010 1010
-
<< 左移运算符:左边丢弃 右边补0
注意:移动的位数 不要 超过自身长度
1010 1100 << 2
10 丢弃<—— |10 1100 <——补 00
-
/>>右移运算符1010 1100 >> 2
补0**|**——> 1010 11 **| **——> 丢弃 00
补1**|**
-
右移分类:逻辑右移 算术右移
-
逻辑右移:右边丢弃 左边补0
-
算术右移:
无符号数:右边丢弃 左边补0
有符号数:
- 正数:右边丢弃 左边补0
- 负数:右边丢弃 左边补1
-
-
右移基本上是右边丢弃 左边补0 只有负数且算右移 左边才会补1。
-
逻辑右移和算术右移 是编译器决定 但是我们可以检测。
综合案例:
将data的第1、5清0,第3、4位 置1 其他为保持不变
unsigned char data = 0xaa ;//1010 1010
用4位二进制数 代替 一位十六进制位
data = data & 1101 1101;
第1、5 清0
1101 1101 = ~(0010 0010) = ~(0010 0000 | 0000 0010)
0010 0000 = 0000 0001 << 5
0000 0010 = 0000 0001 << 1
1101 1101 = ~(0x01 << 5 | 0x01 << 1)
data = data & ~(0x01 << 5 | 0x01 <<1);
第3、4位 置1
data = data | 0001 1000;
0001 1000 = 0001 0000 | 0000 1000
= 0x01 << 4 | 0x01 << 3
data = data | (0x01 <<4 | 0x01 << 3);
-
知识点5【赋值运算符】
-
复合赋值运算符(+=、-=、/=、%=、*=)
a += b; ==> a = a +b;
a *= b; ==> a = a * b
//将 = 右边看做一个整体
void test13() { int data = 3; data *= 3+5; printf("data = %d\n", data); } int main() { test13(); return 0; }
data = 24
知识点6【条件运算符】三元
-
形式:表达式1?表达式2:表达式3
-
语法:先计算表达式1,若成立则计算表达式2;若不成立则计算表达式3.
{ int ret = 0; ret = 3>2?5:6; printf("ret = %d\n", ret); }
ret = 5
-
计算两个整数的最大值
{ int a, b, max; printf("Input a, b:"); scanf("%d,%d", &a, &b); max = a>b ? a : b; printf("max=%d", max); }
Input a, b:1 5 max=5
知识点7【逗号运算符】
-
形式:表达式1, 表达式2 …… 表达式n
-
运算规则:从左往右依次运算,未用括号括起来则取第一个值,用括号括起来则将最后一个表达式的结果看做整个表达式的结果。
void test12() { int data1 = 0; int data2 = 0; data1 = 3, 4, 5, 6; data2 = (3, 4, 5, 6); printf("data1 = %d\n", data1); printf("data2 = %d\n", data2); } int main() { test12(); return 0; }
data1 = 3 data2 = 6
知识点7【自增、自减运算符】
-
++i 或 --i 先加、减 后使用
-
i++ 或 i-- 先使用 后加、减
void test14() { int i = 3; int j = 0; j = ++i; printf("i = %d\nj = %d\n", i, j); } int main() { test14(); return 0; }
i = 4 j = 4
void test15() { int i = 3; int j = 0; j = i++;//j=i, i=i+1 printf("i = %d\nj = %d\n", i, j); } int main() { test15(); return 0; }
i = 4 j = 3
-
i++ 或++i作为单独指令,是没有区别的。
知识点8【运算符优先级】分析已有的代码
-
优先级 高 先执行, 同级别的优先级 要看结合性。
-
运算符的优先级:
- C语言中,运算符的运算优先级共分为15级。
- 1级最高,15级最低。
- 在一个运算量两侧的运算符优先级相同时,则按运算符的结合性所规定的结合方向处理。
-
各运算符的结合性
-
左结合性(从左至右):+ - * /
-
右结合性(从右至左):= ++ –
-
优先级别 | 运算符 | 运算形式 | 结合方向 | 名称或含义 |
---|---|---|---|---|
1 | () | (e) | 圆括号 | |
[] | a[e] | 数组下标 | ||
. | x.y | 成员运算符 | ||
-> | p->x | 自左至右 | 用指针访问成员的指向运算符 | |
2 | - + | -e | 负号和正号 | |
++ – | ++x或x++ | 自增运算、自减运算 | ||
! | !e | 逻辑非 | ||
~ | ~e | 按位取反 | ||
(t) | (t)e | 类型转换 | ||
* | *p | 指针运算,由地址求内容 | ||
& | &x | 求变量的地址 | ||
sizeof | sizeof(t) | 自右至左 | 求某类型变量的长度 | |
3 | * / % | e1*e2 | 自左至右 | 乘、除和求余 |
4 | + - | e1+e2 | 自左至右 | 加、减 |
5 | << >> | e1<<e2 | 自左至右 | 左移、右移 |
6 | < <= > >= | e1<e2 | 自左至右 | 关系运算 |
7 | == != | e1==e2 | 自左至右 | 等于和不等于 |
8 | & | e1&e2 | 自左至右 | 按位与 |
9 | ^ | e1^e2 | 自左至右 | 按位异或 |
10 | | | e1|e2 | 自左至右 | 按位或 |
11 | && | e1&&e2 | 自左至右 | 逻辑与 |
12 | || | e1||e2 | 自左至右 | 逻辑或 |
13 | ? : | e1?e2:e3 | 自右至左 | 条件运算 |
14 | = | x=e | 赋值运算 | |
+= -= *= /= %= >>= <<= &= ^= |= | x+=e | 自右至左 | 复合赋值运算 | |
15 | , | e1,e2 | 自左至右 | 顺序求值运算 |