> 文章列表 > 【C生万物】 操作符篇

【C生万物】 操作符篇

【C生万物】 操作符篇

欢迎来到 Claffic 的博客 💞💞💞

前言: 

我觉得学习语言,最直接的就是懂不懂符号,而符号中最突出的就是操作符,这期带大家认识认识C语言中的操作符及其使用。


目录

Part1:算数操作符

Part2:移位操作符

1.左移操作符

2.右移操作符

Part3:位操作符

Part4:赋值操作符

Part5:单目操作符

Part6:关系操作符

Part7:逻辑操作符

Part8:条件操作符

Part9:逗号表达式

Part10:下标,函数调用,结构成员

1.下标引用操作符[ ]

2.函数调用操作符( )

3.访问结构体成员

Part11:表达式求值

1.隐式类型转换

2.算数转换

3.操作符的属性


Part1:算数操作符

+   -   *   /   %

其实就是常见的加减乘除,再加上一个取模(取余数);

不过它们的使用也遵照一些规则:

•  除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数
• 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
• 操作符的两个操作数必须为整数。返回的是整除之后的余数

Part2:移位操作符

移位操作符包括这两个:

<<     左移操作符
>>     右移操作符

注:移位操作符的操作数只能是整数 

1.左移操作符

位移规则:

左边抛弃,右边补0

实例:

注意:num本身的值不会变化,除非将左移后的结果赋值给num

2.右移操作符

位移规则:

右移运算分为两种类型:

• 逻辑移位
左边用 0 填充,右边丢弃
• 算术移位
左边用原该值的符号位填充,右边丢弃

先说逻辑位移:

 这个还是好理解的

算数位移:

符号位就是最左边的一位,原来的符号位是1,那么右移后补1即可,最后要还原回原码

Part3:位操作符

&     //按位与:只有对应的两个二进位均为1时,结果位才为1,否则为0
|     //按位或:只要对应的二个二进位有一个为1时,结果位就为1,否则为0
^     //按位异或:当两对应的二进位相异时,结果位为1,否则为0

 注:位操作符的操作数只能是整数 

举个例子: 

按位与:

按位或:

按位异或:

对于异或操作符,有下列结论:

位操作符有什么用呢?
这里有一个常见好用的作用:
统计一个整数在存储中二进制的1的个数

#include <stdio.h>
int main()
{int num = -1;int i = 0;int count = 0;//计数while(num){count++;num = num&(num-1);}printf("二进制中1的个数 = %d\\n",count);return 0;
}

Part4:赋值操作符

这种操作符就是方便:

当赋值的对象是本身时,起到修改自身的效果,此时就可以利用赋值操作符。

比如:

int x = 10;
x = x + 2; // 写法1
x += 2;    // 写法2

是不是很简洁?
类似的,有符合赋值操作符:

+=    x = x + n
-=    x = x - n
*=    x = x * n
/=    x = x / n
%=    x = x % n
>>=    x = x >> n
<<=    x = x << n
&=    x = x & n
|=    x = x | n
^=    x = x ^ n

Part5:单目操作符

先看看单目操作符包括哪些吧:

!           逻辑反操作
-           负值
+           正值
&           取地址
sizeof      操作数的类型长度(以字节为单位)
~           对一个数的二进制按位取反
--          前置、后置--
++          前置、后置++
*           间接访问操作符(解引用操作符)
(类型)      强制类型转换

! , - , + , sizeof 不再多说;

取地址&: 

就是字面意思,得到某一个量的地址,在指针那块会经常用到;

二进制按位取反~:

这个意思好理解,就是按照补码,0对应位取反得1,1对应位取反得0,

不过并不常用... ...

前置、后置++/--:

先来解释++/--:

相当于 x += 1 / x -= 1;

在原数的基础上加/减1,原数改变。

那么这个前置和后置是什么意思?

看下面这几段代码:

#include<stdio.h>
int main()
{int i = 10;while (i--){printf("%d ", i);}return 0;
}

输出: 9 8 7 6 5 4 3 2 1 0

#include<stdio.h>
int main()
{int i = 10;while (--i){printf("%d ", i);}return 0;
}

输出:9 8 7 6 5 4 3 2 1

第二种相比第一种少了 0 ;

说明 前置--是先--,再使用后置--是先使用,再--,++相同。

间接访问操作符(解引用操作符) *:

这个操作符就是由地址寻找所指量的操作符

Swap(int* a, int* b) // 传递的是地址
{int tmp = *a; // 解引用操作,通过地址找到a;*a = *b;*b = tmp;
}
int main()
{int a = 10;int b = 20;Swap(&a, &b);printf("a = %d, b = %d", a, b);return 0;
}

Part6:关系操作符

>
>=
<
<=
!=        用于测试“不相等”
==        用于测试“相等”

这部分其实没啥好讲的,

注意判断相等 “==” 不要写成赋值 “=” 。 

Part7:逻辑操作符

就两个:

&&          逻辑与
||          逻辑或

它们与按位操作符是有些相近的:

&        这是按位与

|         这是按位或

两边放表达式还是好理解的,如果放数字呢?

像 1 && 2 ,1与2都是非0,都为真,逻辑与操作后是真,返回1;

1 || 0 ,1为真,0为假,逻辑或操作后是真,返回1;

Part8:条件操作符

exp1 ? exp2 : exp3

这个条件操作符其实就是三目操作符啦

它就相当于:

if (exp1)exp2;
elseexp3;

Part9:逗号表达式

exp1, exp2, exp3, …expN

逗号表达式就是用逗号把表达式隔开;

从左向右执行;

整个表达式的结果是最后一个表达式的结果

可以看一个实例:

int main()
{//代码1int a = 1;int b = 2;      // a = 12      b = 13int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式printf("%d\\n", a);printf("%d\\n", b);printf("%d\\n", c);return 0;
}

输出结果:12   13   13

Part10:下标,函数调用,结构成员

1.下标引用操作符[ ]

int arr[10];//创建10个元素的数组
arr[9] = 10;//使用下标引用操作符。
//[ ]的两个操作数是arr和9。

2.函数调用操作符( )

接受一个或者多个操作数:

第一个操作数是函数名,剩余的操作数就是传递给函数的参数。 

#include <stdio.h>
void test1()
{printf("Hello world\\n");
}
void test2(const char* str)
{printf("%s\\n", str);
}
int main()
{test1();			 // 使用()作为函数调用操作符。test2("abcdef"); return 0;
}

3.访问结构体成员

.      结构体.成员名
->     结构体指针->成员名
struct Stu
{char name[10];int age;char sex[5];
};int main()
{struct Stu stu;struct Stu* pStu = &stu;//结构成员访问stu.age = 20;//结构成员访问pStu->age = 20;//结构成员访问return 0;
}

Part11:表达式求值

1.隐式类型转换

先说什么是整型提升:

C 的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为 整型提升。

再来看看整型提升是如何进行的:

整形提升是按照变量的数据类型的符号位来提升的。

//负数的整形提升
char c1 = -1; // 一个char类型1个字节大小,8个比特位
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001//无符号整形提升,高位补0

2.算数转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换
// 排名看先后
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
但是算数转换要合理

3.操作符的属性

说一个操作符有什么属性,也就是有什么影响的因素:

• 操作符的优先级
• 操作符的结合性
• 是否控制求值顺序
两个相邻的操作符先执行哪个?取决于他们的优先级;
如果两者的优先级相同,取决于他们的结合性。

操作符优先级表:

// 表达式1
a*b + c*d + e*f;
代码 1 在计算的时候,由于 * + 的优先级高,只能保证, * 的计算是比 + 早,但是优先级并不
能决定第三个*比第一个+早执行。
//表达式2
c + --c;

同上,操作符的优先级只能决定自减--的运算在+的运算的前面,但是我们并没有办法得知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义

的。
//代码3-非法表达式
int main()
{int i = 10;i = i-- - --i * ( i = -3 ) * i++ + ++i;printf("i = %d\\n", i);return 0;
}

这个结果取决于编译器,这里就不展示结果,因为没有参考价值。 


总结: 

这篇博客进行了操作符的讲解,不要问操作符为什么长这样,能理解的理解并尝试取用一下,不能理解的先好好记住,刚开始有操作符不会用是很正常的,建议多走读代码,进而自己能敲出自己的代码~

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

Free Fonts