目录

+ - * / %
- #include
- int main()
- {
- int a = 10 / 3;//除法操作符,两边都是整数就执行整数除法
- printf("%d\n", a);
- double b = 10.0 / 3;//两边只要有一个是浮点数就能计算出小数
- printf("%lf\n", b);
- printf("%.1lf\n", b);//在lf前面加.1能保留小数点后一位,.几就保留几位
- return 0;
- }
输出结果:
- 输出:
- 3
- 3.333333
- 3.3
-
- #include
- int main()
- {
- int ret = 10 % 3;//取模,操作符两边必须是整数
- printf("%d\n,ret");
- return 0;
- }
输出结果:
输出:1
在讲移位前,需要知道一些基本的概念:
二进制:
二进制整数有三种表示形式:
1. 原码
2. 反码
3. 补码
而在内存中存储的是:二进制的补码
所以参数在移位时是二进的补码。
例:
- int main()
- {
- //整形类型占四个字节(32个比特位),二进制的表现形式:
-
- int a = 10;
- //00000000000000000000000000001010 - 原码
- //00000000000000000000000000001010 - 反码
- //00000000000000000000000000001010 - 补码
-
- int a = -10;
- //10000000000000000000000000001010 - 原码
- //11111111111111111111111111110101 - 反码
- //11111111111111111111111111110110 - 补码
-
- return 0;
- }
通过观察发现正数原码、反码、补码相同,
负数反码是:原码符号位不变,其它位按位取反,补码是:反码+1。
例:
- #include
- int main()
- {
- //左移操作符:<<
- //规则:左边抛弃,右边补零
-
- int a = 10;
- //a:
- //00000000000000000000000000001010 - 补码
-
- int b = a << 1;
- //b:
- //00000000000000000000000000010100 - 补码
-
- printf("%d\n", b);
-
- int c = -10;
- //c:
- //10000000000000000000000000001010 - 原码
- //11111111111111111111111111110101 - 反码
- //11111111111111111111111111110110 - 补码
-
- int d = c << 1;
- //d:
- //11111111111111111111111111101100 - 补码
- //11111111111111111111111111101011 - 反码
- //10000000000000000000000000010100 - 原码
-
- printf("%d\n", d);
-
- return 0;
- }
(注:printf 打印出来给我们看的是原码。)
输出结果:
- 输出:
- 20
- -20
总结:
左移操作也可以看成是乘二的操作。
例:
- #include
- int main()
- {
- //右移操作符:>>
- //1.算数右移:左边补符号位,右边抛弃(常用)
- //2.逻辑右移:左边补零,右边抛弃
-
- int a = 10;
- //a:
- //00000000000000000000000000001010 - 补码
-
- int b = a >> 1;
- //b:
- //00000000000000000000000000000101 - 补码
-
- printf("%d\n", b);
-
- int c = -10;
- //c:
- //10000000000000000000000000001010 - 原码
- //11111111111111111111111111110101 - 反码
- //11111111111111111111111111110110 - 补码
-
- int d = c >> 1;
- //d:
- //11111111111111111111111111111011 - 补码
- //11111111111111111111111111111010 - 反码
- //10000000000000000000000000000101 - 原码
-
- printf("%d\n", d);
-
- return 0;
- }
输出结果:
- 输出:
- 5
- -5
注:无论是右移还是左移的位数都不能为负数。
例:
- ret>>-1
- 这样写是错误的
& 按位与
| 按位或
^ 按位异或
例:
- #include
- int main()
- {
- //& - 按二进制与
- //规则:有零则零
- int a = 3;
- //00000000000000000000000000000011 - 补码
-
- int b = -5;
- //10000000000000000000000000000101 - 原码
- //11111111111111111111111111111010 - 反码
- //11111111111111111111111111111011 - 补码
-
- int c = a & b;
- //00000000000000000000000000000011 - a 补码
- //11111111111111111111111111111011 - b 补码
-
- //00000000000000000000000000000011 - c 原码
-
- printf("%d\n", c);
- return 0;
- }
输出结果:
输出:3
例:
- #include
- int main()
- {
- // | - 按二进制位或
- // 规则:有一则一
-
- int a = 3;
- //00000000000000000000000000000011 - 补码
-
- int b = -5;
- //10000000000000000000000000000101 - 原码
- //11111111111111111111111111111010 - 反码
- //11111111111111111111111111111011 - 补码
-
- int c = a | b;
- //00000000000000000000000000000011 - a补码
- //11111111111111111111111111111011 - b补码
-
- //11111111111111111111111111111011 - c补码
- //11111111111111111111111111111010 - c反码
- //10000000000000000000000000000101 - c原码
-
- printf("%d\n", c);
-
- return 0;
- }
输出结果:
输出:-5
例:
- #include
- int main()
- {
- // ^ - 按二进制位异或
- // 规则:相同为零,相异为一
-
- int a = 3;
- //00000000000000000000000000000011 - 补码
-
- int b = -5;
- //10000000000000000000000000000101 - 原码
- //11111111111111111111111111111010 - 反码
- //11111111111111111111111111111011 - 补码
-
- int c = a ^ b;
- //00000000000000000000000000000011 - a补码
- //11111111111111111111111111111011 - b补码
-
- //11111111111111111111111111111000 - c补码
- //11111111111111111111111111110111 - c反码
- //10000000000000000000000000001000 - c原码
-
- printf("%d\n", c);
-
- return 0;
- }
输出结果:
输出:-8
练习:
一道编程题:
如何不创建临时变量完成两个数的交换
例:
- #include
- int main()
- {
- int a = 3;
- int b = 5;
-
- printf("%d %d\n", a, b);
-
- a = a ^ b;
- b = a ^ b;// b = a ^ b ^ b // 而 a ^ b ^ b = a 所以b就赋值为a
- a = a ^ b;// a = a ^ b ^ a // 而 a ^ b ^ a = b 所以a就赋值为b
-
- printf("%d %d\n", a, b);
-
- return 0;
- }
输出结果:
- 输出:
- 3 5
- 5 3
用异或操作符交换两个变量的弊端:
1. 可读性差
2. 效率没有创建临时变量高
3. 异或只能用于整数变量的交换
总结:这种方法了解即可,平时使用临时变量交换两个变量的方法更好。
赋值操作符能给变量赋值。
例:
- int main()
- {
- int a = 10;
- a = 100;// = 能将a赋值成100
- return 0;
- }
还有复合赋值符:
例:
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
这些运算符都可以写成复合的效果(规则都是一样的)
例:
- int main()
- {
- int a = 10;
- a += 10;//这个其实就是:a = a + 10
- printf("%d\n", a);//输出的结果就是20
- return 0;
- }
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
+ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
例1:
- #include
- int main()
- {
- //! 逻辑反操作
- //C语言中0表示假,非零表示真
- int n = 0;
- if (n)
- {
- printf("1\n");
- }
- if (!n)//!逻辑反操作,将假变为真(也能从真变假)
- {
- printf("2\n");
- }
- return 0;
- }
输出结果:
输出:2
例2:
- #include
- int main()
- { // + -
- int a = -10;
- printf("%d\n", a);
- printf("%d\n", -a);
- printf("%d\n", +a);//‘+’几乎没有用处
- return 0;
- }
输出结果:
- 输出:
- -10
- 10
- -10
例3:
-
- #include
- int main()
- {
- // ~ 按位取反
- //00000000000000000000000000000000
- //11111111111111111111111111111111 - 补码是全1
-
- int a = 0;
- printf("%d\n", ~a);
-
- }
输出结果:
输出:-1
例4:
- #include
- int main()
- {
- //++
- int a = 10;
- int b = a++;//后置++,先使用,再++
- printf("%d\n", b);
- printf("%d\n", a);
-
- int c = 10;
- int d = ++c;//前置++,先++,再使用
- printf("%d\n", d);
- printf("%d\n", c);
- return 0;
- }
输出结果:
- 输出:
- 10
- 11
- 11
- 11
注:-- 的规则与 ++ 是一样的。
- #include
-
- int main()
- {
- // ++ -- 是带有副作用的
- // 会改变变量自身的值
-
- //1
- int a = 10;
- int b = ++a;//b=11 a=11
-
- //2
- int a = 10;
- int b = a + 1;//b=11 a=10
-
- return 0;
- }
例5:
- #include
- int main()
- { // (类型)强制类型转换
- int a = (int)3.14;//这样编译器就不会报警告
-
- srand((unsigned int)time(NULL));//将类型为time_t的time转成srand需要的无符号整形
-
- return 0;
- }
例:
- #include
- void test1(int arr[])//本质上传过来的是数组首元素的地址
- {
- printf("%d\n", sizeof(arr));//地址在32位环境占4个字节
- } //在64位的环境中占8个字节
- void test2(char ch[])
- {
- printf("%d\n", sizeof(ch));//我是32位的环境,所以输出4
- }
- int main()
- {
- int arr[10] = { 0 };
- char ch[10] = { 0 };
- printf("%d\n", sizeof(arr));//int类型占4个字节
- printf("%d\n", sizeof(ch));//char类型占1个字节
- test1(arr);
- test2(ch);
- return 0;
- }
输出结果:
- 输出:
- 40
- 10
- 4
- 4
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”
注:别把 “==” 和 “=” 给写错了。
&& 逻辑与 ( a&&b a,b都要满足才真)
|| 逻辑或 ( a||b a,b只要满足一个就真)
例:
- #include
- int main()
- {
- int i = 0, a = 0, b = 2, c = 3, d = 4;
-
- i = a++ && ++b && d++;
- //因为a=0,++的优先级较低,所以(a++)这个表达式值是0,而&&有零那就是零了,
- //所以(++b)(d++)都不会发生
- printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
-
- return 0;
- }
输出结果:
- 输出:
- a = 1
- b = 2
- c = 3
- d = 4
- #include
- int main()
- {
- int i = 0, a = 1, b = 2, c = 3, d = 4;
-
- i = a++ || ++b || d++;
- //(a++)这个表达式为真,那||左边就无须计算了
- //所以(++b)(d++)都不计算了
- printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
-
- return 0;
- }
输出结果:
- 输出:
- a = 2
- b = 2
- c = 3
- d = 4
exp1 ? exp2 : exp3
例:
这是一个求较大值的代码:
- #include
-
- int max(int a, int b)
- {
- if (a > b)
- return a;
- else
- return b;
- }
-
- int main()
- {
- int a = 10;
- int b = 20;
- printf("%d\n", max(a, b));
- return 0;
- }
输出结果:
输出:20
而用条件操作符:
- #include
-
- int max(int a, int b)
- {
- return (a > b ? a : b);//如果a>b则取a,否则取b
- }
-
- int main()
- {
- int a = 10;
- int b = 20;
- printf("%d\n", max(a, b));
- return 0;
- }
输出结果:
输出:20
两种写法是一模一样的。
逗号表达式:
1. 用逗号隔开的多个表达式。
2. 从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
例:
- #include
-
- int main()
- {
- int a = 1;
- int b = 2;
- int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
- //先算a = b + 10,算出a = 12,再算b = a + 1,算出b = 13,
- //最后结果就是最后一个表达式(b = a + 1)的值
- printf("c = %d\n", c);
- return 0;
- }
输出结果:
输出:13
结构体在C语言中一般用于描述复杂对象,比如人、书,C语言中没有这样的类型,
但是结构体能让我们创建新的类型。

CPU在进行运算的时候一般使用整形int,所以在有些时候,当一个小于整形的类型进行计算时,计算机就会先进行整形提升再进行运算,这就是隐式类型转换。
(通用CPU是难以直接实现两个非整形的直接相加运算)
例:
- // char short int long ...
- // 1 2 4
- int main()
- {
- //char --> signed char
- char a = 3;
- //截断
- //00000000000000000000000000000011
- //00000011 - a
- //
- char b = 127;
- //00000000000000000000000001111111
- //01111111 - b
-
- char c = a + b;
- //00000011
- //01111111
- //整型提升
- //00000000000000000000000000000011 - a
- //00000000000000000000000001111111 - b
- //00000000000000000000000010000010 - a + b =c
- //截断
- //10000010 - c
- printf("%d\n", c);
- //%d 是打印十进制的整数
- //11111111111111111111111110000010 - 补码
- //11111111111111111111111110000001 - 反码
- //10000000000000000000000001111110 - 原码
- //-126
- return 0;
- }
输出结果:
输出:-126
注:
char:
有符号的char的取值范围是:-128~127
无符号的char的取值范围是:0~255
不同操作类型的数进行运算时会进行算数转换:
long double
double
float unsigned long int
long int
unsigned int
int
注:算数转换不合理会产生一些问题:
- #include
-
- int main()
- {
- float f = 3.14;
- int num = f;//隐式转换,会有精度丢失
- printf("%d\n", num);
- return 0;
- }
输出结果:
输出:3
复杂表达式的求值有三个影响的因素:
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序
但是,我们写出的代码如果没有唯一的运算路径,就会出问题
所以,总结:平时写代码的运算路径要唯一。
以上就是本篇文章的内容了,感谢你的阅读。
如果喜欢本文的话,欢迎点赞和评论,写下你的见解。
如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。
之后我还会输出更多高质量内容,欢迎收看。