Day3
什么是运算符?
运算符就是用来表示某种运算的符号
+ - * / ....
什么是表达式?
用运算符连接的式子就叫做表达式,确切的名字以表达式中最低运算符来确定
1+2、3/4
操作数
参与运算的数据
几目运算符
该运算符需要几个操作数就是几目运算符
优先级
如果有多个运算符出现在一个表达式中,运算符优先级就决定优先进行哪种运算
结合性:
决定先算那个操作数,后算哪个操作数
左到右 、 右到左
基本语句
#include <stdio.h>
int main()
{
scanf("%d",&变量);
printf("jcgsjhvj%\n");
//代表一行注释
/*
这一对符号中的所有东西都是注释
*/
return 0;
}
1、算术运算符(双目、左到右)
用来进行数学上的算术运算的运算符
+ - * / %(取余/取模)
注意几点:
1./、% 右边不能为 0
2.% 两边的操作数必须是整型数据
3.进行 / 运算,如果两个数其中数为小数,结果一定是小数
如果两个数其中数为整数,结果也是整数,那么想让商为小数怎么办?
把其中一个操作数强转为小数
例:
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
5 > 9
6 != 6
5 > 3
...
关系表达式可以成立也可以不成立,
如果成立表示这个关系表达式的值是1
如果不成立表示这个关系表达式的值是0
关系表达式的值: 0 或 1
6 != 6 ---> 0
5 > 2 ---> 1
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决定式子的结果
4、赋值运算符(双目、右到左) =
左边的操作数一定是变量(左值)
int m=10;
m=20;
m=30;
int n;
n=m;
m=1.5自动取整
一般来说,“=”两边操作数类型要一致,或者兼容
用赋值运算符连起来的是赋值表达式。
赋值表达式的值,是赋值完成后左边操作数的值。
复合赋值运算符,赋值运算符可以和其他运算符结合使用。构成复合的赋值运算符。
+= -= *= /=
如:
int a;
a += 5;<--->a = a + 5;
a -= 5;<--->a = a - 5;
单目运算符: ++(自增 1) --(自减 1) 包含赋值运算
后++ 前++
int m,n; int a,b;
m = 5; a = 5;
n = m++; b = ++a;
前++的表达式是+1后的值,后++的表达式是+1前的值。
int a = 8;
printf("a = %d\n",++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
& 取地址符 单目运算符
* 解引用运算符 单目运算符
. 取成员变量
-> 取成员变量