【C生万物】 操作符篇

简介: 【C生万物】 操作符篇

c3010e27dcef4f002ec72d8caa43e7ca_491a35e80c7f4e969f99b463e2cb36d8.png


前言:

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


目录

Part1:算数操作符

Part2:移位操作符

1.左移操作符

2.右移操作符

Part3:位操作符

Part4:赋值操作符

Part5:单目操作符

Part6:关系操作符

Part7:逻辑操作符

Part8:条件操作符

Part9:逗号表达式

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

1.下标引用操作符[ ]

2.函数调用操作符( )

3.访问结构体成员

Part11:表达式求值

1.隐式类型转换

2.算数转换

3.操作符的属性



Part1:算数操作符


+   -   *   /   %


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

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

•  除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。

• 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。

• % 操作符的两个操作数必须为整数。返回的是整除之后的余数


Part2:移位操作符


移位操作符包括这两个:

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


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

1.左移操作符


位移规则:

左边抛弃,右边补0

实例:

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


2.右移操作符


位移规则:

右移运算分为两种类型:

逻辑移位

左边用0填充,右边丢弃

• 算术移位

左边用原该值的符号位填充,右边丢弃

先说逻辑位移:

d4e85edb22593c24785b8adbe0345b5f_fbd66e84882249709d3414eff37dae48.png

这个还是好理解的

算数位移:

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


Part3:位操作符


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


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

举个例子:

按位与:

2776873e4e124ca8bcc675e0a0b617d7_183b67a8be3f47e5ad04498f301b392d.png

按位或:

90c69a9569d4cd6f000398d34a6fee58_335892832cd94f4c9e9344d5984b3704.png

按位异或:

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

6597c3e1301826789340a6c63e82f0cb_ba4dd2f62b164d3dba4bfb6b014bf968.png

位操作符有什么用呢?

这里有一个常见好用的作用:

统计一个整数在存储中二进制的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.操作符的属性


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

• 操作符的优先级

• 操作符的结合性

• 是否控制求值顺序

两个相邻的操作符先执行哪个?取决于他们的优先级;

如果两者的优先级相同,取决于他们的结合性。

操作符优先级表:

79bc99680973c52c469e3b4cc2c502fb_20434c192a52461e998f8fe88c05b322.png

bf1a5754598d6ff82d8c4933701f1184_bbc404e5e2dd4951b23393b5dab71a1a.png

// 表达式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;
}

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


总结:

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

目录
相关文章
|
6月前
|
存储 C语言
【C生万物】数组
【C生万物】数组
|
11月前
|
算法 安全 Java
C生万物 | 指针进阶 · 提升篇-1
C生万物 | 指针进阶 · 提升篇
54 0
|
11月前
|
小程序 Linux C语言
C生万物 | 指针进阶 · 提升篇-3
C生万物 | 指针进阶 · 提升篇
61 0
|
11月前
|
编译器 C++
C生万物 | 指针进阶 · 提升篇-2
C生万物 | 指针进阶 · 提升篇
42 0
|
11月前
|
存储 编译器 C语言
C生万物 | 指针进阶 · 炼狱篇-1
C生万物 | 指针进阶 · 炼狱篇
87 0
|
11月前
|
存储 编译器 C语言
C生万物 | 指针进阶 · 炼狱篇-3
C生万物 | 指针进阶 · 炼狱篇
69 0
|
11月前
C生万物 | 指针进阶 · 炼狱篇-2
C生万物 | 指针进阶 · 炼狱篇
51 0
|
11月前
|
存储 编译器 C++
C生万物 | 聊聊枚举与联合体的用法
C生万物 | 聊聊枚举与联合体的用法
51 0
|
存储 编译器 C语言
【C生万物】 数组篇
【C生万物】 数组篇
89 0
【C生万物】 数组篇
|
Dart Unix 编译器
C生万物 | 操作符汇总大全【庖丁解牛,精细讲解】
✒C语言操作符汇总大全,全程精析讲解,拨开云雾见天明☀
95977 10
C生万物 | 操作符汇总大全【庖丁解牛,精细讲解】