C语言 08 运算符
基本运算符
基本运算符包含常用的一些操作,常用的有:
- 加法运算符:+
- 减法运算符:-
- 乘法运算符:*
- 除法运算符:/
- 取模运算符:%
- 赋值运算符:=
先来看加法运算,这个就和数学中的是一样的了:
#include <stdio.h>
int main() {
int a = 10, b = 5;
printf("%d", a + b);
}
15
当然也可以像数学中那样写在一个数或是变量的最前面,表示是正数:
int a = +10, b = +5;
不过默认情况下就是正数,所以没必要去写一个 + 号
减法运算符其实也是一样的:
#include <stdio.h>
int main() {
int a = 10, b = 5;
printf("%d", a - b);
}
5
接着我们来看看乘法和除法运算:
#include <stdio.h>
int main() {
int a = 20, b = 10;
printf("%d, %d", a * b, a / b);
}
200, 2
还有取模运算:
#include <stdio.h>
int main() {
int a = 20, b = 8;
printf("%d", a % b);
}
4
取模运算就是计算余数
不过很遗憾,在 C 中没有指数相关的运算符,一般通过循环来实现。
运算符优先级
和数学中一样,运算符是有优先级的:
#include <stdio.h>
int main() {
int a = 20, b = 10;
printf("%d", a + a * b);
}
220
如果没有优先级,那么结果应该是400,但结果为220,说明先进行了乘法运算,再进行了加法运算,存在运算符优先级
在数学中,如果需要优先计算加减法再计算乘除法,那么就需要使用括号来提升加减法的优先级,C 语言也可以:
#include <stdio.h>
int main() {
int a = 20, b = 10;
printf("%d", (a + a) * b);
}
400
优先计算 a + a 的结果,再乘以 b
总结一下,运算符优先级如下,从左往右依次递减:
()
> + - (做正负表示)
> * / %
> + - (做加减运算)
> =
根据上面的优先级,我们来看看下面 a 的结果是什么:
#include <stdio.h>
int main() {
int c;
int a = (3 + (c = 2)) * 6;
printf("%d", a);
}
30
#include <stdio.h>
int main() {
int b, c;
int a = (b = 5, c = b + 8);
printf("%d, %d, %d", a, b, c);
}
13, 5, 13
逗号运算符从前往后依次执行,赋值结果是最后边的结果
自增自减运算符
正常情况下想要让一个变量值自增需要:
int a = 10;
a = a + 1;
现在只需要替换为:
int a = 10;
// 使用自增运算符,效果等价于 a = a + 1
++a;
并且它也是有结果的,除了做自增运算之外,它的结果是自增之后的值:
#include <stdio.h>
int main() {
int a = 10;
// 等价于int b = a = a + 1;
int b = ++a;
printf("%d", b);
}
11
当然也可以将自增运算符写到后面,和写在前面的区别是,它是先返回当前变量的结果,再进行自增的,顺序是完全相反的:
#include <stdio.h>
int main() {
int a = 10;
int b = a++;
printf("a = %d, b = %d", a, b);
}
a = 11, b = 10
自增运算符++在前,那么先自增再出结果;自增运算符++在后,那么先出结果再自增。
那要是不想自增 1 而是自增 2 或是其他的数字呢?可以使用复合赋值运算符:
int a = 10;
// 等价于a = a + 5;
a += 5;
复合赋值运算符不仅仅支持加法,还支持各种各样的运算:
#include <stdio.h>
int main() {
int a = 10;
// 可以复合各种运算
a %= 3;
printf("a = %d", a);
}
a = 1
自减运算与自增运算同理:
#include <stdio.h>
int main() {
int a = 10;
a--;
printf("a = %d", a);
}
a = 9
自增自减运算符和 +、- 做符号是的优先级一样,仅次于 () 运算符,所以在编写时一定要注意:
#include <stdio.h>
int main() {
int a = 10;
int b = 5 * --a;
printf("b = %d", b);
}
b = 45
位运算符
当想要让一个变量的值变成 2 倍,只需要做一次乘法运算即可:
int a = 10;
// 很明显算完之后a就是20了
a *= 2;
但是现在可以利用位运算来快速进行计算:
int a = 10;
a = a << 1; //也可以写成复合形式 a <<= 1
这样运算之后得到的结果居然也是 20,这是咋算出来的呢?实际上 << 是让所有的 bit 位进行左移操作,上面就是左移 1 位:
10 = 0000 1010 现在所以 bit 位上的数据左移一位 0001 0100 = 20
当然能左移那肯定也可以右移:
#include <stdio.h>
int main() {
int a = 6;
// 右移其实就是除以2的操作
a = a >> 1;
printf("a = %d", a);
}
a = 3
除了移动操作之外,也可以进行按位比较操作,先来看看按位与操作:
#include <stdio.h>
int main() {
int a = 6, b = 4;
// 按位与操作
int c = a & b;
printf("c = %d", c);
}
按位与是根据每个 bit 位来进行计算的:
4 = 00000100
6 = 00000110
按位与实际上就是让两个数的每一位都进行比较,如果两个数对应的bit位都是 1,那么结果的对应 bit 位上就是 1,其他情况一律为 0
所以计算结果为:00000100 = 4
除了按位与之外,还有按位或运算:
#include <stdio.h>
int main() {
int a = 6, b = 4;
int c = a | b;
printf("%d", c);
}
6
按位或也是根据每个 bit 位来进行计算的:
4 = 00000100
6 = 00000110
按位或实际上也是让两个数的每一位都进行比较,如果两个数对应 bit 位上其中一个是 1,那么结果的对应bit位上就是 1,其他情况为 0。
所以计算结果为:00000110 = 6
还有异或和按位非(按位否定):
#include <stdio.h>
int main() {
int a = 6, b = 4;
// 注意^不是指数运算,表示按位异或运算,让两个数的每一位都进行比较
// 如果两个数对应 bit 位上不同时为 1 或是同时为 0,那么结果就是 1,否则结果就是 0,所以这里的结果就是 2
int c = a ^ b;
// 按位否定针对某个数进行操作,它会将这个数的每一个 bit 位都置反,0 变成 1,1 变成 0
a = ~a;
printf("%d, %d", c, a);
}
2, -7
按位运算都是操作数据底层的二进制位来进行的。
逻辑运算符
逻辑运算符用于计算真和假,比如今天要么下雨要么不下雨,现在想要在程序中判断一下是否下雨了,这时就需要用到逻辑运算符:
#include <stdio.h>
int main() {
int a = 10;
// 现在想要判断 a 的值是否小于 0,可以直接使用小于符号进行判断,最后得到的结果只能是 1 或 0
_Bool c = a < 0;
// 虽然结果是一个整数,但是这里推荐使用 _Bool 类型进行接收,它只能表示 0 和 1(更加专业一些)
printf("c = %d", c);
}
c = 0
实际上在 C 语言中,0 一般都表示为假,而非 0 的所有值(包括正数和负数)都表示为真,上面得到 1 表示真,0 表示假。
除了小于符号可以判断大小之外,还有:<
、 <=
、>=
、>
比如现在想要判断字符 C 是否为大写字母:
#include <stdio.h>
int main() {
char c = 'D';
// 由于底层存储的就是 ASCII 码,这里可以比较 ASCII 码,也可以写成字符的形式
printf("c是否为大写字母:%d", c >= 'A');
}
c是否为大写字母:1
但是发现,现在判断只能判断一个条件,也就是说只能判断 c 是否是大于等于 A
的,但是不能同时判断 c 的值是否是小于等于 Z
的,所以这时,就需要利用逻辑与和逻辑或来连接两个条件了:
#include <stdio.h>
int main() {
char c = 'D';
// 使用 && 表示逻辑与,逻辑与要求两边都是真,结果才是真
printf("c是否为大写字母:%d", c >= 'A' && c <= 'Z');
}
c是否为大写字母:1
又比如现在希望判断 c 是否不是大写字母:
#include <stdio.h>
int main() {
char c = 'D';
// 使用 || 表示逻辑或,只要两边其中一个为真或是都为真,结果就是真
printf("c是否不为大写字母:%d", c < 'A' || c > 'Z');
}
c是否不为大写字母:0
当然也可以判断 c 是否为某个字母:
#include <stdio.h>
int main() {
char c = 'D';
// 注意判断相等时使用==双等号
printf("c是否为字母A:%d", c == 'A');
}
c是否为字母A:0
判断不相等也可以使用:
printf("c是否不为字母A:%d", c != 'A');
也可以对某个结果取反:
#include <stdio.h>
int main() {
int i = 20;
// 使用!来对结果取反,注意!优先级很高,一定要括起来,不然会直接对i生效
printf("i是否不小于20:%d", !(i < 20));
}
i是否不小于20:1
这里要注意一下!如果直接作用于某个变量或是常量,那么会直接按照上面的规则(0 表示假,非 0 表示真)非 0 一律转换为 0,0 一律转换为 1。
这里可以结合三目运算符来使用这些逻辑运算符:
#include <stdio.h>
int main() {
int i = 0;
// 三目运算符格式为:expression ? 值1 : 值2,返回的结果会根据前面判断的结果来的
char c = i > 10 ? 'A' : 'B';
// 这里是判断 i 是否大于 10,如果大于那么 c 的值就是 A,否则就是 B
printf("%d", c);
}
66
最后,总结一下前面认识的所有运算符的优先级,从上往下依次降低:
运算符 | 解释 | 结合方式 |
---|---|---|
() | 同数学中的括号,直接提升到最高优先级 | 由左向右 |
! ~ + + – + - | 否定,按位否定,增量,减量,正负号 | 由右向左 |
* / % | 乘,除,取模 | 由左向右 |
+ - | 加,减 | 由左向右 |
<< >> | 左移,右移 | 由左向右 |
< <= >= > | 小于,小于等于,大于等于,大于 | 由左向右 |
== != | 等于,不等于 | 由左向右 |
& | 按位与 | 由左向右 |
^ | 按位异或 | 由左向右 |
| | 按位或 | 由左向右 |
&& | 逻辑与 | 由左向右 |
|| | 逻辑或 | 由左向右 |
? : | 条件 | 由右向左 |
= += -= *= /= &= ^= |= <<= >>= | 各种赋值 | 由右向左 |
, | 逗号(顺序) | 由左向右 |