1. 算数操作符
如:+ - * / %
这里着重讲解下 / 和 % 操作符,上代码:
#include<stdio.h> int main() { int m = 10 % 3; // %---取余(两端必须是整数) printf("%d\n", m); // 1 int n = 10 / 3; // /---取商 printf("%d\n", n); // 3 // 当 /(除号)两端是整数的时候,执行的是整数的除法,两端只要有一个浮点数,执行的就是浮点数的除法 double z = 10.0 / 3; printf("%lf\n", z); // 3.333333 return 0; }
2. 移位操作符
注:移位操作符的操作数只能是整数。
引言:
整数有3种二进制的表示形式
1:原码
2:反码
3:补码
对于正整数 - 原码 - 反码 - 补码 均相同
对于负整数 - 原码 - 反码 - 补码 不同,要进行计算!
如+5: 整数,整型,32bit
00000000000000000000000000000101 ---原码---反码---补码
如-5: 整数,负数
10000000000000000000000000000101 ---原码
11111111111111111111111111111010 ---反码(原码的符号位不变,其他按位取反)
11111111111111111111111111111011 ---补码(反码的二进制+1)
整数在内存中存储的是补码!!!
2.1 右移操作符 (>>)
移位规则: 首先右移运算分两种:
1. 逻辑移位 (左边用0填充,右边丢弃)
2. 算术移位 (左边用原该值的符号位填充,右边丢弃)
#include<stdio.h> int main() { int a = 5; int b = a >> 1; printf("%d\n", b); //输出2 return 0; }
我们来画张图解释下吧:
2.2 左移操作符 (<<)
原理同右移操作符
移位规则: 左边抛弃、右边补0
上代码:
#include<stdio.h> int main() { int a = 5; //把a在内存中存储的二进制位向左移动2位 int b = a << 2; //此时此刻b的二进制为00000000000000000000000000010100 //换成10进制表示20 printf("%d", b);//打印或使用用的是原码的值 20 return 0; }
3. 位操作符
& 按位与
| 按位或
^ 按位异或
// -5的原码 10000000000000000000000000000101
// -5的反码 11111111111111111111111111111010
// -5的补码 11111111111111111111111111111011
// 3的补码 00000000000000000000000000000011
// &按位与:有0为0,全1为1。
// c = -5&3: 00000000000000000000000000000011
// c的内存存的是补码,打印的是原码 上述补码是正数,原码反码补码相同
// |按位或:有1为1,全0为0
// ^相同为0,相异为1
// c的内存存的是补码,打印的是原码
上代码:
#include<stdio.h> int main() { int a = 3; int b = -5; int m = a & b; int n = a | b; int k = a ^ b; printf("%d\n", m); // 3 printf("%d\n", n); // -5 printf("%d\n", k); // -8 return 0; }
画图解析:
//练习:
//交换两个整型变量(不能创建临时变量)
法一:临时变量法 效率高
#include<stdio.h> int main() { int a = 3; int b = 5; int c = 0; printf("交换前a=%d b=%d\n", a, b); //交换前a=3 b=5 c = a; a = b; b = c; printf("交换后a=%d b=%d\n", a, b); //交换后a=5 b=3 return 0; }
法二:(此法存在溢出的问题)
#include<stdio.h> int main() { int a = 3; int b = 5; a = a + b; b = a - b; a = a - b; printf("a=%d b=%d", a, b); return 0; }
法三:异或操作符 (仅限于整数)
// 3^3=0
// 0^5=5
#include<stdio.h> int main() { int a = 3; int b = 5; a = a ^ b; b = a^ b; //即为 a ^ b ^ b = a ^ 0 = a a = a ^ b; //即为 a ^ a ^ b = 0 ^ b = b printf("a=%d b=%d", a, b); }
4. 赋值操作符
赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。
int weight = 120;//体重 weight = 89;//不满意就赋值 double salary = 10000.0; salary = 20000.0;//使用赋值操作符赋值 //赋值操作符可以连续使用,比如: int a = 10; int x = 0; int y = 20; a = x = y+1;//连续赋值 //这样的代码感觉怎么样? //那同样的语义,你看看: x = y+1; a = x; //这样的写法是不是更加清晰爽朗而且易于调试。
复合赋值符:+= -= *= /= %= >>= <<= &= |= ^=
这些运算符都可以写成复合的效果。 比如:
int x = 10; x = x+10; x += 10;//复合赋值 //其他运算符一样的道理。这样写更加简洁。
5. 单目操作符
! (逻辑反操作)
#include<stdio.h> int main() { int flag = 0; if (!flag) printf("hehe\n"); // hehe return 0; }
-(负值)
#include<stdio.h> int main() { int i = 0; int flag = 1; for (i = 0; i < 10; i++) { printf("%d ", i * flag); flag = -flag; } return 0; } // abs 对整数求绝对值 // fabs 对小数求绝对值
sizeof(操作符的类型长度,以字节为单位)
#include<stdio.h> int main() { int a = 10; printf("%d\n", sizeof(a)); //4字节 printf("%d\n", sizeof(int)); //4字节 int arr[10] = { 1,2,3,4,5,6 }; printf("%d\n", sizeof(arr)); //40字节 printf("%d\n", sizeof(int[10])); //40字节 }
~ 按位取反
#include<stdio.h> int main() { int a = 0; // ~ 按(内存中补码的二进制)位取反 // 00000000000000000000000000000000 // 11111111111111111111111111111111 补码 // 11111111111111111111111111111110 反码 // 10000000000000000000000000000001 原码 printf("%d\n", ~a); // -1 return 0; }
#include<stdio.h> int main() { int a = 10; // 00000000000000000000000000001010 // 00000000000000000000000000000100 --- 1<<2得到左边 // 00000000000000000000000000001110 // 11111111111111111111111111111011 --- ~(1<<2) // 00000000000000000000000000001010 a = a | (1 << 2); printf("%d\n", a); // 14 a = a & ~(1 << 2); printf("%d\n", a); // 10 return 0; }
++ 和 -- 运算符
上代码:
#include<stdio.h> int main() { int a = 3; int b = a++; //后置++ ,先使用,后++ printf("a= %d,b=%d\n", a, b); // a=4 b=3 return 0; } #include<stdio.h> int main() { int a = 3; int b = ++a; //前置++, 先++,后使用 printf("a=%d b=%d\n", a, b); // a=4,b=4 return 0; } //--类似
* 简介访问操作符(解引用操作符)
#include<stdio.h> int main() { int a = 10; int* p = &a; *p = 120; // *p解引用操作符 printf("%d\n", a); // 120 return 0; }
()强制类型转换
#include<stdio.h> int main() { int a = (int)3.14; //3.14 - double -> int a printf("%d\n", a); // 3 return 0; }
练习:
#include<stdio.h> int main() { int a = 10; int* p = NULL; printf("%d\n", !2); // 0 printf("%d\n", !0); // 1 a = -a; p = &a; printf("%d\n", sizeof(a)); // 4 printf("%d\n", sizeof(int)); // 4 printf("%d\n", sizeof a); // 4 //printf("%d\n", sizeof int); err }
#include<stdio.h> void test1(int arr[]) { printf("%d\n", sizeof(arr)); //(2) 4 } void test2(char ch[]) { printf("%d\n", sizeof(ch)); //(4) 4 } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("%d\n", sizeof(arr)); //(1) 40 printf("%d\n", sizeof(ch)); //(3) 10 test1(arr); test2(ch); return 0; }
6. 关系操作符
7. 逻辑操作符
&& 逻辑与
|| 逻辑或
要特别区分逻辑操作符和位操作符,&&相当于是两个条件都要满足才可完成的指令,而||相当于两个条件只要有一个完成就可以。
//代码一:逻辑与 #include<stdio.h> int main() { int age = 0; scanf("%d", &age); if (age > 0 && age < 18) { printf("未成年\n"); } return 0; return 0; } //代码二:逻辑或 #include<stdio.h> int main() { int month = 4; if (month < 1 || month>12) { printf("输入错误\n"); } else { } }
// 小练习: #include<stdio.h> int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; //134行代码好比老师让三个同学都去完成一个任务,若其中任何一个没完成,就算任务失败 //当a++时,先使用=0,为假,则后面不予考虑 printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d); // 1 2 3 4 //i = a++ || ++b || d++; 若有一个满足,后面不予考虑 //printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d); // 2 2 3 4 return 0; }
8. 条件操作符
#include<stdio.h> int main() { int a = 10; int b = 20; int max = 0; max = (a > b ? a : b); /*if (a > b) { max = a; } else max = b;*/ printf("%d\n", max); // 20 return 0; }
9. 逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
上代码:
//代码1 #include<stdio.h> int main() { int a = 3; int b = 5; int c = 6; int d = (a += 2, b = a - c, c = a + 2 * b); printf("%d\n", d); // 3 return 0; } //代码2 #include<stdio.h> int main() { int a = 1; int b = 2; int c = (a > b, a = b + 10, a, b = a + 1); // 13 printf("%d\n", c); // 13 return 0; }
10.下标引用、函数调用和结构成员
1:下标引用:
#include<stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%d\n", arr[7]); // 8 //arr[7]-- > * (arr + 7)-- > * (7 + arr)-- > 7[arr] //解释:因为arr是数组名,访问的的首元素的地址,arr+7即是第八个元素的地址,即 * (arr + 7) // 又因为加法交换律支持加号两边变换位置,即* (7 + arr),又可写成7[arr]。----装逼用 printf("%d\n", arr[7]); // 8 printf("%d\n", 7[arr]); // 8 return 0; }
2:函数调用:
#include<stdio.h> void test() { printf("hehe\n"); } int Add(int x, int y) { int z = 0; return z = x + y; } int main() { test(); //函数调用操作符 int ret = Add(2, 3); printf("%d\n", ret); return 0; }
3: 结构成员访问操作符:
#include<stdio.h> struct stu { char name[20]; int age; double score; }; int main() { struct stu s = { "zhangsan", 20, 85.5 }; // . printf("%s %d %.1lf\n", s.name, s.age, s.score); // 结构体变量.结构体成员 // -> struct stu* ps = &s; printf("%s %d %.1lf\n", (*ps).name, (*ps).age, (*ps).score); //此方法写起来过于繁琐 printf("%s %d %.1lf\n", ps->name, ps->age, ps->score); //运用->可较为方便 }