【万字讲解c语言操作符,堪称操作符“百科全书”】(上)

简介: 【万字讲解c语言操作符,堪称操作符“百科全书”】

一、操作符分类


2. 算数操作符

有 + - * / %

要注意的是

除法

1.整数除法(除号的两端都是整数)

2.浮点数除法(除号的两端只要有一个是小数就执行小数除法)

举例如下

int main()
{
   int r = 7 / 2;
   printf("%d\n", r);//打印3
   double d = 7 / 2;
   printf("%lf\n", d);//打印3
   double d = 7.0 / 2.0;
   printf("%lf\n", d);//打印3.5
   return 0;
}

除法中除数不能为零

举例如下

int main()
{
  int n = 0;
  int r = 5 / n;
  return 0;//编译器会报错
}

%

得到的是整除后的余数

要注意:% 取模操作符的两个操作数必须都是整数

举例如下

int main()
{
   int r = 15 % 8;
   printf("%d\n", r);//得到7
   return 0;
}

3. 位移操作符

3.1 >>

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

举例如下

int main()
{
  int a = 15; 
  int b = a >> 1;//移动就是a中的2进制信息,并且>>左右都是整数,不能是小数
  return 0;
}

要计算移位还要知道一个知识点:

计算机,能够处理的是二进制的信息,如1和0。

15 就是十进制

例如:

那么15的二进制就是:

一个整形是4个字节 = 32bit位

那么15放进a里面要凑够32个bit位要怎么写呢?

规定:最高位是0表示它是正数,最高位是1表示它是负数

所以15的二进制表示形式如下:

00000000000000000000000000001111

而整数的二进制表达形式: 有三种表达形式

1.原码:正数,最高位为0;负数,最高位为1

2.反码:原码的符号位不变,其他位按位取反(也就是说原来是1的变成0,原来是0的变成1)

3.补码:反码+1

正整数的原码、反码、补码是相同的

负整数的原码、反码、补码是要计算的

所以15的原码,反码,补码都是:00000000000000000000000000001111

举例子:

int main()
{
  int a = 15;
00000000000000000000000000001111 - 原码
00000000000000000000000000001111 - 反码
00000000000000000000000000001111 - 补码
  int b = -15;
10000000000000000000000000001111 - 原码
11111111111111111111111111110000 - 反码(原码的符号位不变,其他位按位取反得到的就是反码)
11111111111111111111111111110001 - 补码(反码+1就是补码)
    return 0;
//}

要注意:整数在内存中存储的是补码
计算的时候也是使用补码计算的


所以移位移动的是二进制的补码

int main()
{
  int a = 15;
  int b = a >> 1;
  printf("%d\n", b);//7
  printf("%d\n", a);//15
  return 0;
}

上面的代码,a向右移动一位,b=7,a=15

下面是移动的方法:

右移分为两种

1.算数右移(右边丢弃,左边补原来的符号位)

2.逻辑右移(右边丢弃,左边直接补0)

C语言没有明确规定到底是算数右移还是逻辑右移,一般编译器上采用的是算术右移

右移之后,就变成了00000000000000000000000000000111

通过计算就得到了b=7,而a依然是15,这个运算不会让a的值变化

举一个负数例子:

int main()
{
  int a = -15;
  int b = a >> 1;
  printf("%d\n", b);//-8
  return 0;
}

我们是对-15的补码进行移动

补码右移得到b的二进制序列:11111111111111111111111111111000

但这是b的补码,我们还要推算出原码

补码-1就是反码:11111111111111111111111111110111

反码按位取反就是原码:10000000000000000000000000001000

再按照二进制的计算方法,结果为b = -8


3.2 <<

左移相对右移就相对简单一点

左移的移动原理:左边丢弃,右边补0

举例:

int main()
{
  int a = 6;
  int b = a << 1;
  printf("%d\n", b);
  return 0;
}

a的二进制序列:00000000000000000000000000000110

左移得到b:00000000000000000000000000001100

正数的原反补码相同,所以b=12,a不变为6

警告:对于一位运算符,不要移动负数位,这个是标准未定义的。

nt main()
{
  int a = 5;
  int b = a >> -2;//标准未定义行为
  return 0;
}

4.位操作符

也是操作二进制位


4.1 &按位与 计算方法

int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码
  int c = a & b;
  //& -- 对应二进制位有0则为0,两个同时为1,才是1
  //00000000000000000000000000000011 -a补码
  //11111111111111111111111111111011 -b补码
  //00000000000000000000000000000011 -c补码
  //符号位是0为正数,原反补相同
  printf("%d\n", c);//计算的是原码,c=3
  return 0;
}

4.2 | 按位或 计算方法

int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101
  //11111111111111111111111111111010
  //11111111111111111111111111111011 - 补码
  //
  int c = a | b;
  //| - 按(2进制)位或 - 对应的二进制位有1则为1,两个同时为0才是0
  //00000000000000000000000000000011 - a补码
  //11111111111111111111111111111011 - b补码
  //11111111111111111111111111111011 - 得到c补码
  //11111111111111111111111111111010 - 反码
  //10000000000000000000000000000101 - 原码 -5
  printf("%d\n", c);//-5
  return 0;
}

4.3 ^ 按位异或计算方法

int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码
  //
  int c = a ^ b;
  //^ - 按(二进制)位异或 -对应的二进制位相同为0,相异为1
  //00000000000000000000000000000011 -a补码
  //11111111111111111111111111111011 -b补码
  //11111111111111111111111111111000 -得到c补码
  //11111111111111111111111111110111 -c反码
  //10000000000000000000000000001000 -c原码 -8
  printf("%d\n", c);//-8
  return 0;
}

举一个题目看看是怎么应用叭:

不能创建临时变量(第三个变量),如何实现两个数的交换?

交换2个整型变量,正常情况下是这样写的:

int main()
{
  int a = 3;
  int b = 5;
  printf("交换前:a=%d b=%d\n", a, b);
  int tmp = a;
  a = b;
  b = tmp;
  printf("交换后:a=%d b=%d\n", a, b);
  return 0;
}

而题目要求不能创建临时变量,我们可以这样写:

int main()
{
  int a = 3;
  int b = 5;
  printf("交换前:a=%d b=%d\n", a, b);
  a = a + b;
  b = a - b;
  a = a - b;
  printf("交换后:a=%d b=%d\n", a, b);
  return 0;
}

但缺点就是容易溢出

也有第③种写法,运用到 ^ 的知识

int main()
{
  int a = 3;
  int b = 5;
  printf("交换前:a=%d b=%d\n", a, b);
  a = a ^ b;
  b = a ^ b;
  a = a ^ b;
  printf("交换后:a=%d b=%d\n", a, b);
  return 0;
}

如下图说明:

用异或实现交换的原理就是:

1.两个相同的数异或为0

2.任何数异或0都等于那个数

但这种例子可读性不高,效率也不如第一种好。

5.赋值操作符

赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的值,也就是你可以给自己重新赋值。

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值

赋值操作符可以连续使用,比如:

int a = 10

int x = 0;

int y = 20;

a = x = y+1;//连续赋值(先把y+1的结果赋给x,再把x的结果赋给a)

但更推荐下面这种赋值方式:

x = y+1;

a=x;

这样的写法是不是更加清晰爽朗而且易于调试。


5.1 复合赋值符

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

这些运算符都可以写成复合的效果

比如:

int x = 10;
x = x+10;
x += 10;//复合赋值
//其他运算符一样的道理。这样写更加简洁

6. 单目操作符

只有一个操作数

6.1 单目操作符介绍

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

! 逻辑反操作 (把假变成真,把真变成假)

int main()
{
  int flag = 0;//假
  if (flag == 0)//为真,打印hehe
  {
    printf("hehe\n");
  }
  if (!flag)//flag为假,但!flag为真,打印hehe
  {
    printf("hehe\n");
  }
  if (flag)//假,不打印
  {
    printf("haha\n");
  }
  return 0;
}

-负值   +正值
int main()
{
  int a = 5;
  int b = -a;
  printf("%d\n", b);//b=-5
  return 0;
}

& * 应用于指针

int main()
{
  int a = 10;
  //pa是指针变量
  int* pa = &a;//&-取地址操作符 - 取出a的地址 - 存在pa里-pa的类型写成int * - *告诉我pa是指针变量 - int告诉我pa指向的那个对象a的类型是int 
  *pa = 20;//解引用操作符(间接访问操作符)-单目操作符-通用pa中存放的地址,找到指向的空间(内容)
  int c = *pa;
  return 0;
}

sizeof

int main()
{
  int a = 10;
  printf("%d\n", sizeof(int));//4
  ❌错误写法:printf("%d\n", sizeof int);//类型时括号不能去掉
  printf("%d\n", sizeof(a));//4
  printf("%d\n", sizeof a);//括号可以去掉,说明sizeof不是函数-函数后面的括号不能去掉
  return 0;
}

sizeof还可以计算数组大小

int main()
{
  int arr[10] = {0};
  printf("%d\n", sizeof(arr));//40 - 数组名表示单独放在sizeof内部,计算整个数组的大小单位字节
  printf("%d\n", sizeof(int [10]));//40
  return 0;
}

~ 按补码二进制位取反

int main()
{
  int a = 0;//正数
  printf("%d\n", ~a);
  //00000000000000000000000000000000 -a补码
  //11111111111111111111111111111111 - ~a补码
  //11111111111111111111111111111110 - ~a补码-1得到反码
  //10000000000000000000000000000001 - ~a反码按位取反得到原码
  return 0;
}
相关文章
|
6天前
|
C语言
C语言之操作符1
C语言之操作符1
22 0
|
6天前
|
编译器 C语言
操作符详解(C语言基础深入解析)
操作符详解(C语言基础深入解析)
|
6天前
|
存储 编译器 C语言
爱上C语言:操作符详解(下)
爱上C语言:操作符详解(下)
|
6天前
|
算法 测试技术 C语言
【C语言】异或(^)操作符
【C语言】异或(^)操作符
18 0
|
4天前
|
C语言
C语言——算术操作符
C语言——算术操作符
9 0
|
6天前
|
编译器 C语言
C语言操作符2
C语言操作符2
5 0
|
6天前
|
C语言
条件操作符和逻辑操作符(C语言零基础教程)
条件操作符和逻辑操作符(C语言零基础教程)
|
6天前
|
编译器 C语言
爱上C语言:操作符详解(上)
爱上C语言:操作符详解(上)
|
6天前
|
存储 编译器 C语言
C语言操作符详解(下)
C语言操作符详解(下)
27 0
|
6天前
|
编译器 C语言 索引
C语言操作符详解(上)
C语言操作符详解(上)
48 0