一.名词解析
什么是运算符?
运算符就是用来表示某种运算的符号
+ - * / ....
什么是表达式?
用运算符连接的式子就叫做表达式,确切的名字以表达式中最低运算符来确定
1+2、3/4
操作数
参与运算的数据
几目运算符
该运算符需要几个操作数就是几目运算符
优先级
如果有多个运算符出现在一个表达式中,运算符优先级就决定优先进行哪种运算
结合性:
决定先算那个操作数,后算哪个操作数
左到右、右到左
#include <stdio.h>
int main()
{
scanf("%d",&变量);
printf("jcgsjhvj%\n");
//代表一行注释
/*
这一对符号中的所有东西都是注释
*/
return 0;
}
二、算数-关系-逻辑-赋值运算符
1、算术运算符
用来进行数学上的算术运算的运算符
+ - * / %(取余/取模) 双目运算符
注意几点:
/、% 右边不能为 0
% 两边的操作数必须是整型数据
进行/ 运算,如果两个数其中数为小数,结果一定是小数
如果两个数其中数为整数,结果也是整数,那么想让商为小数怎么办?
把其中一个操作数强转为小数
例:
int a = 10;
int b = 20,c = 30; //int b = 20; int c = 30;
printf("%d + %d = %d\n",a,b,a+b);
printf("%d - %d = %d\n",a,b,a-b);
printf("%d * %d = %d\n",a,b,a*b);
printf("%d / %d = %d\n",a,b,a/b);
printf("%d / %d = %f\n",a,b,(float)a/b);
printf("%d %% %d = %d\n",a,b,a%b);
算术运算符的结合性:左到右
2、关系运算符
用来判断两个数据的大小的运算符
< <= > >= ==(注意) !=
双目运算符 ,关系运算符的结合性:左到右
用关系运算符连接起来的式子---> 关系表达式
例:
a > b
a < b
5 > 9
6 != 6
5 > 3
...
关系表达式可以成立也可以不成立,
如果成立表示这个关系表达式的值是1
如果不成立表示这个关系表达式的值是0
关系表达式的值:0 或 1
6 != 6 ---> 0
5 > 2 ---> 1
8 > 6 > 4 关系表达式没问题,但是不成立
1 > 4 不成立 0 C语言中,数学上没问题
6 < 8 并且 6 > 4
并且如何表示?
3、逻辑运算符
&& || !
与 或 非
并且 或者 取反
&& 、 || 是双目运算符
&& 两个结果都为真才是真,否则就是假的
|| 有一个为真就为真,只有两个都为假的时候才是假
! 是单目运算符一个操作数
操作数为真,结果为假;操作数为假,结果为真
0是假 非0是真
用逻辑运算符连起来的就叫逻辑表达式
逻辑表达式结果:0 或者 1 0代表表达式为假,1代表表达式为真
例:
int a = 3;
int b = 4;
a && b --> 真
!a --> 假
!b || a --> 真
练习:
int a,b,c,d,e,f = 6;
a = 1;
b = 2;
c = 3;
d = 4;
(e = (a > b)) && (f = (c > d))
表达式以及e,f的结果
表达式的值为0, e = 0, f = 6
逻辑运算符是"惰性运算符"
如果事先知道了结果,就不会做后面表达式
(e = (a < b)) || (f = (c > d))
e = 1,表达式的值为1,f = 6
(1) a && b && c
只有a 为真,才会判断b,如果b为真,才会判断c ,c决定式子的结果
只要a 为假,整个式子的结果就为假
a && b 整个式子的结果就为假
(2)a || b || c
只有a为假,才会判断b,如果b为假,才会判断c ,c决定式子的结果
int a,b,c,d,e,f,m,n,l;
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
f = 6;
m = 7;
n = 8;
l = 9;
(m = (a < b)) || (n = (c > d)) && ( l = (e != f))
&& 优先级 高于 ||
m = (a < b)) || ((n = (c > d)) && ( l = (e != f))
m = 1
n = 8
l = 9
3 + 4 * 5 = 3 + (4 * 5) = 23
4、赋值运算符
= 双目运算符,结合性右到左
注意:赋值运算符,左边的操作数一定是变量(左值)
int m = 10;
m = 20;
m = 30;
int n;
n = m;
10 = m; //错误的
m = 1.5; //自动取整
一般来说,“=” 两边操作数类型要一致,或者兼容
m = 'a';
用赋值运算符连起来的就是赋值表达式
赋值表达式的值:是赋值完成后的左边操作数的值
int a , b;
a = b = 10; //相当于先做了 b = 10 , 然后 a = b
b + 5 = 10; //错误的
--------------
复合赋值运算符,赋值运算符可以和其他运算符结合使用,构成复合的赋值运算符
+= -= *= /= ....
如:
int a;
a += 5; <==> a = a + 5;
a -= 5; <==> a = a - 5;
10 += 20; 10 + 10 = 20 //错误的
单目运算符: ++ -- 包含赋值运算
++ 自增1
-- 自减1
只需要一个操作数 可以在左边,也可以在右边
后++ 前++
int m,n; int a,b;
m = 5; a = 5;
n = m++; b = ++a;
n = 5; b = 6;
m = 6; a = 6;
因为对于m,a来说,++的效果都是+1 所以是6
不同是前++ 的表达式是 +1 后的值, 后 ++ 的表达式是 +1 前的值
int a = 8;
printf("a = %d\n",++a); //9
printf("a = %d\n",a++); //9
printf("a = %d\n",a); //10
a = 0;
a++,a-- 成立
5、位运算符
位运算是指把操作数按bit 位 (先换算成二进制补码) 进行一个运算
注意:位运算的操作数必须是整数(char、short、int......)
& 按位与
| 按位或
~ 按位取反
^ 按位异或
上面几个不会产生进位和借位
<< 按位左移
>> 按位右移
除了~ 之外都是双目运算符
所有位运算符都需要转成二进制补码,才能运算
(1) ~ 按位取反
0 --> 1
1 --> 0
例:
int a = 3;
// 00...00 0011
int b = ~3;
// 11...11 1100
//-1 11...1 1011
// 100..0000 0100 -4
b = -4;
int m = -5;
// 000...000 0101
// 111...111 1010
//+1 111...111 1011
int n = ~m;
// 000...000 0100
n = 4;
(2)& 按位与
a 和 b 都是一个bit a&b 值如下所示
a b a&b
1 1 1
1 0 0
0 0 0
0 1 0
对应bit位同为1才为1
3 & 5
3 0000 0011
5 0000 0101
& ---------
0000 0001
char a = -6;
// 0000 0110
// 1111 1001
// 1111 1010
char b = 10;
// 0000 1010
a & b 10
1111 1010
0000 1010
& ---------
0000 1010
结论:
两个bit 同为1 结果才是1 否则就是 0
一个bit 位与 1 进行 & 运算结果是原来的值
一个bit 位与 0 进行 & 运算结果是0
练习:
int 的变量 a 把 a 的 从低位开始第5个bit 位变为0 其他位不变,怎么办
xxxx xxxx xxxx xxxx xxxx xxxx xxxX xxxx
1111 1111 1111 1111 1111 1111 1110 1111
& ----------------------------------------
a & 0xffffffef
a = a & 0xffffffef;
a &= 0xffffffef;
(3) | 按位或
a 和 b 都是一个bit a|b 值如下所示
a b a|b
1 1 1
1 0 1
0 0 0
0 1 1
只要有一个bit位为1就为1
3 | 5
3 0000 0011
5 0000 0101
| ---------
0000 0111
int a = 15,b = 16;
a | b
0000 1111
0001 0000
| ----------
0001 1111 31
结论:
两个bit 同为 0 结果才是0 否则就是 1
一个bit 位与 1 进行 | 运算结果是 1
一个bit 位与 0 进行 | 运算结果是原来的值
练习:
int 的变量 a 把 a 的 从低位开始第5个bit 位变为1 其他位不变,怎么办
xxxx xxxx xxxx xxxx xxxx xxxx xxxX xxxx
0000 0000 0000 0000 0000 0000 0001 0000
| ----------------------------------------
a = a | 0x00000010;
(4)^ 按位异或
求异 不同为1 ,相同为 0
a 和 b 都是一个bit a^b 值如下所示
a b a^b
1 1 0
1 0 1
0 0 0
0 1 1
结论:
一个bit 位和 0 进行 ^,原来的值
一个bit 位和 1 进行 ^,值相反
练习:
int 的变量 a 把 a 的 从低位开始第5个bit 位取反 其他位不变,怎么办
xxxx xxxx xxxx xxxx xxxx xxxx xxxX xxxx
0000 0000 0000 0000 0000 0000 0001 0000
^ ----------------------------------------
a = a ^ 16;
(5) << 按位左移
x << n 把x按 bit 位整体左移 n 个 bit
运算时就需要,先把x变成补码,n不需要
例:
int m = 20;
m << 3;
m: 000...000 0001 0100 16 + 4 2^4 + 2^2
左移时,高位超出的就舍弃,低位补0
000...000 1010 0000 128+32 2^7 + 2^5 = 160
如果左移时,高位舍弃的全是0,对应把需要左移的数乘以 2^n
练习:
有一个int 变量 a ,把 a 的 bitn([0,31]) 变为1 ,其他的 bit 不动
a = a | (1 << n);
有一个int 变量 a ,把 a 的 bitn([0,31]) 变为0 ,其他的 bit 不动
a = a & (~(1 << n))
xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
1111 1111 1111 1111 1111 1111 1110 1111
0000 0000 0000 0000 0000 0000 0001 0000
& ---------------------------------------
(6) >> 按位右移
x >> n 把x按 bit 位整体右移 n 个 bit
运算时就需要,先把x变成补码,n不需要
低位丢掉,高位会空缺
如果数据是有符号的话,高位就补符号位
如果数据是无符号的话,高位就补0
例:
int m = -3;
// 3的补码: 000...000 0011
// 3补码取反 111...111 1100
// -3的补码: 111...111 1101
m >> 10;
// 111...111 1111
m = -1;
unsigned int n = -3;
// 3的补码: 000...000 0011
// 3补码取反 111...111 1100
// -3的补码: 111...111 1101
n >> 10;
// 0000 0000 00 111...111 1111
n = 2 ^ 22 -1;
交换2个 int 变量的值
(1) int x = 3,y = 5;
int z = x;
x = y;
y = z;
(2) int x = 3,y = 5; // 交换后两数的和以及积不会变的
x = x + y;
y = x - y; //x + y - y = x;
x = x - y; //x + y - x = y;
(3) int x = 3,y = 5; //利用位运算
1 ^ 1 = 0;
2 ^ 2 = 0;
n ^ n = 0;
0 ^ x = x;
1 ^ x = ~x;
x = x ^ y;
0011
0101
x = 0110
y = x ^ y; //y = x ^ y ^ y = y ^ y ^ x = 0 ^ x = x;
0110
0101
y = 0011
x = x ^ y; //x = x ^ y ^ (x ^ y ^ y) = (x ^ x) ^ (y ^ y) ^ y = 0 ^ 0 ^ y = y;
0110
0011
y = 0101
6、条件运算符(问号运算符)
"? :" 三目运算符,需要三个操作数结合性右到左
语法:
表达式1 ? 表达式2 : 表达式3
怎么理解?
先判断? 前的表达式1的是否成立,
如果成立的话,就只执行表达式2 ,整个表达式的值就是表达式2的值
如果不成立的话,就只执行表达式3 ,整个表达式的值就是表达式3的值
例:
(3 > 5) ? 2 : 1
int m = 10;
int n = 20;
int c ;
c = (m > n ? m : n); //求最大值
7、逗号运算符
双目运算符,优先级最低,结合性左到右
语法:
表达式1 , 表达式2
逗号运算符的执行顺序左到右,先执行表达式1,再执行表达式2;
整个逗号表达式的值是表达式2的值
例:
int a = 10;
int b = 20;
a = 10,b = 20; //逗号表达式
int c ;
c = a = 10,b = 20;
int c = (a = 10,b = 20);
8、其它运算符
sizeof
sizeof(类型)
求该类型的数据所占的字节数目
sizeof(short) ---> 2
或者
sizeof(值)
求该值对应类型的所占字节数目
sizeof('a') <---> sizeof(char) --> 1
sizeof(a) <---> sizeof(int) --> 4
typeof 求一个变量/常量的类型
int a = 100;
typeof(a); ---> int
typeof(100); ---> int
typeof('a'); ---> char
.......
强制转换运算符
(目标类型)值
(int)3.1415 = 3;
float f = 3.14;
f + 3.1 --->6.24
(int)f + 3.1 --->6.1
(int)(f + 3.96) --->7
& 取地址符 单目运算符
* 解引用运算符 单目运算符
. 取成员变量
-> 取成员变量