前言:
我觉得学习语言,最直接的就是懂不懂符号,而符号中最突出的就是操作符,这期带大家认识认识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; else exp3;
Part9:逗号表达式
exp1, exp2, exp3, …expN
逗号表达式就是用逗号把表达式隔开;
从左向右执行;
整个表达式的结果是最后一个表达式的结果
可以看一个实例:
int main() { //代码1 int a = 1; int b = 2; // a = 12 b = 13 int 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; }
这个结果取决于编译器,这里就不展示结果,因为没有参考价值。
总结:
这篇博客进行了操作符的讲解,不要问操作符为什么长这样,能理解的理解并尝试取用一下,不能理解的先好好记住,刚开始有操作符不会用是很正常的,建议多走读代码,进而自己能敲出自己的代码~