C语言各类操作符全面讲解
目录
- 1 算术操作符
- 2 移位操作符
- 3 位操作符
- 4 赋值操作符
- 5 单目操作符
- 5.1 ! 逻辑反操作
- 5.2 sizeof 和数组
- 6 关系操作符
- 7 逻辑操作符
- 8 条件操作符
- 9 逗号表达式
- 10 下标引用函数调用和结构成员
- 10.1 [ ]下标引用操作符
- 10.2 ()函数调用操作符
- 10.3 访问一个结构的成员
- 11 表达式求值
- 11.1 整形提升
- 11.2 优先级和结合性
- 总结
1 算术操作符
+ - * / %
+,-和*操作数我就不多说了,这里我们重点来 / 和%
/操作数
作用:就是求商
注意点:
1 二边的操作数都是整形,商的结果就为整数
2 二边的操作数有一个是浮点型结果就为小数
%操作数
作用:求余数
注意点:. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
2 移位操作符
<< 左移操作符
>> 右移操作符
注意:移位操作符移的是二进制位,且操作数只能是整数
<< 左移操作符
规则:左边抛弃、右边补0
代码举例:
#include<stdio.h> int main() { int a = -5; //正数的原码,反码和补码都相同 //这是负数的规则: //10000000000000000000000000000101原码 //11111111111111111111111111111010反码(原码的符号位不变,其他位按位取反) //11111111111111111111111111111011补码(反码+1就是补码) int b = a << 1; //11111111111111111111111111110110补码 //11111111111111111111111111110101反码 //10000000000000000000000000001010原码 printf("a = %d\n", a); printf("b = %d\n", b); return 0; }
当a<<1时
当a<<2时
当a<<3时
总结:
1 操作数被移位操作符操作后其值仍然不变
2 计算机存储的都是补码,而打印出来的是原码所对应的值
3 b=a<<n时,b的值位a*2^n,也就是说当我们左移1位时相当与乘了个2倍
>> 右移操作符
移位规则: 首先右移运算分两种:
1. 逻辑移位 左边用0填充,右边丢弃
2. 算术移位 左边用原该值的符号位填充,右边丢弃
代码举例:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int a = -64; int b = a >> 1; printf("a = %d\n", a); printf("b = %d\n", b); return 0; }
当a>>1时
当a>>2时
当a>>3时
总结:
1 右移操作和左移操作是本质都是对补码的二进制位进行操作
2 b=a>>n时,b的值位a/2^n,也就是说当我们左移1位时相当与除了个2倍
注意:
对于移位运算符,不要移动负数位,这个是标准未定义的。
3 位操作符
& //按位与
| //按位或
^ //按位异或
注:他们的操作数必须是整数。
我们这些位操作符都是针对操作数的补码进行操作的
&操作符
作用:对于二进制数,都为0才为0都为1才为1
代码举例:
#include<stdio.h> int main() { int a = 5; //00000000000000000000000000000101 5的补码 int b = -3; //10000000000000000000000000000011 3的原码 //11111111111111111111111111111100 3的反码 //11111111111111111111111111111101 3的补码 int c = a & b; //00000000000000000000000000000101 5的补码 //11111111111111111111111111111101 3的补码 // &的作用是二进制数,都为0才为0都为1才为1 //00000000000000000000000000000101 c的补码 printf("a = %d\n", a); printf("b = %d\n", b); printf("c = %d\n", c); return 0; }
|按位或
作用:二进制位中有一个为1就为1,
^按位异或
作用:二进制位中相异置1,相同为置0
大家知道这些操作符的作用了,我们来做到题目来实战一下吧。
题目1:不能创建临时变量(第三个变量),实现两个数的交换
代码实现:
#include<stdio.h> int main() { int a = 2; //0010 int b = 3; //0011 printf("交换前a = %d,b = %d \n", a, b); a = a ^ b; //a的值0001 b = a ^ b; //b的值0010(2) a = a ^ b; //a的值0011(3) printf("交换后a = %d,b = %d\n", a, b); return 0; }
题目2:编写代码实现:求一个整数存储在内存中的二进制中1的个数。
代码实现:
//num&1便会找到二进制最低位是否为1 #include<stdio.h> int main() { int num = -1; int i = 0; int count = 0;//计数 for (i = 0;i < 32;i++) { if (num & (1 << i)) { count++; } } printf("二进制数中1的个数:count = %d\n", count); return 0; }
总结:
我们要想看二进制中的最低位是1还0,我们就可以通过&1来实现。
4 赋值操作符
=
这个操作符是用来赋值的,我们要于‘==’区分,这个是用来表示相等的,大家是否在编程的时候会弄错呢?下面教大家一种写法可以在很大程度上避免这种错误。
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int a = 1; if (1 == a) { printf("可以避免错误\n"); } }
要是我们写成1=a,就会报下面的错误,这样我们就能够及时的改正自己的错误,是不是很好呢。
复合赋值符
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
这些都是=操作符的复合形式,举个例子。
a+=10;就相当于a=a+10;
a-=10;就相当于a=a-10;
5 单目操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
单目操作符的操作对像是1个,下面我们来一一细说。
5.1 ! 逻辑反操作
就是让真变假,假变真
代码举例:
#include<stdio.h> int main() { int a = 0; int b = 1; int c = !a; int d = !b; printf("c = %d,d = %d\n", c, d); return 0; }
5.2 sizeof 和数组
sizeof是用来求操作数的类型长度(以字节为单位)
下面我们来看到这段代码
#include <stdio.h> void test1(int arr[]) { printf("%d\n", sizeof(arr));//(2) } void test2(char ch[]) { printf("%d\n", sizeof(ch));//(4) } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("%d\n", sizeof(arr));//(1) printf("%d\n", sizeof(ch));//(3) test1(arr); test2(ch); return 0; }
他们的结果分别是 40 10 4 4,为什么呢?
第一个我们求的是整的数组的大小,arr有10个元素,每个元素都是整形,所有数组的大小为40个字节。
第二个ch有10个元素,每给个元素为char 类型,所以ch数组大小为10字节
第三个和第四个传的是数组名(本质上都是首元素地址),那么对于test1和test2应该用指针来接收,所以在test1和test2其实求的是指针的大小,在32平台,指针的大小应该为4个字节。
6 关系操作符
>
>=
< <=
!= 用于测试“不相等”
== 用于测试“相等”
7 逻辑操作符
&& 逻辑与
|| 逻辑或
用一道例题来说明逻辑操作符
#include <stdio.h> int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; //i = a++||++b||d++; printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d); return 0; }
为什么b= 2,c= 3,d =4呢?我们不是进行来对bcd进行了前置++或者后置++的操作吗?
这是因为对于&&来说只要他的左表达式为假了,后面就不在执行。
而对于||来说只要左表达式为真,后面就不在执行了
8 条件操作符
xp1 ? exp2 : exp3
这个意思就是如果xp1为真,就执行exp2,否则就执行exp3。
9 逗号表达式
exp1, exp2, exp3,.......expN
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
10 下标引用函数调用和结构成员
10.1 [ ]下标引用操作符
操作数:一个数组名 + 一个索引值
对于一个已经初始化的数组来说,arr[7]和7[arr]及*(arr+7)都是等价的。
#include<stdio.h> int main() { int arr[10] = { 0 }; arr[7] = 5; printf("arr[7] = %d\n", arr[7]); 7[arr] = 6; printf("arr[7] = %d\n", arr[7]); *(arr + 7) = 7; printf("arr[7] = %d\n", arr[7]); return 0; }
10.2 ()函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
10.3 访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
11 表达式求值
对于一给表达式我们一般要考虑它的计算操作符的优先级和结合性,当表达式进行求值的时候还可能会发生整形提升。
11.1 整形提升
什么是整形提升呢?就是在计算的计算的过程中都是默认以整形的方式进行计算的,当我是char类型参与计算时候就要发生整形提升。
整形提升规则:
负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是: 11111111111111111111111111111111
正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char 所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是: 00000000000000000000000000000001
无符号整形提升,高位补0
11.2 优先级和结合性
对于应该复杂表达式的求值有三个影响的因素。
1. 操作符的优先级
2. 操作符的结合性
3. 是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
那么我们知道了解复杂表达式的3个元素,那么表达式求数的结果一定说唯一的吗?
下面我们来看到问题表达式:
int c = 1;
int b = c+ --c;
请问b中的值是什么?
b=1?b=0?为什么二个结果呢?
对--操作符的优先级是比+高的,但是并没有规定系统是怎么给C准备空间的,如果开始为就表达中的c开辟了空间,那么结果就为1,如果是在--c之后在开辟空间的,那么结果就为0。
这些问题表达式我们要谨防在我们的代码中出现。
总结
对于这些操作符,不是看完这篇博客将能掌握的,大家还是要在写代码多练习。
到此这篇关于C语言各类操作符全面讲解的文章就介绍到这了,更多相关C语言操作符内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!