目录
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); //运用->可较为方便
}