c语言分层理解(c语言操作符)(1)

简介: 1. 操作符分类操作符有这么几类:算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用、函数调用、结构成员。下面对这些操作符一一细细道来。

1. 操作符分类

操作符有这么几类:

算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用、函数调用、结构成员。

下面对这些操作符一一细细道来。

2. 算术操作符

+ - * / %

这五个都是常见的算术操作符,但是有两个符号需要特别注意:/和%。

看图得结论:


01fa8e07ab026d90e9d33c1b521bc050.png

1.除了%操作符,其他的四个操作符可以用于整数和浮点数。


730521101bc8620122752c22afe11f1c.png

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


dfef59e68a0d55d57dc7e8be6dcb6792.png

3.%操作符的两个操作数必须是整数,返回的是整除之后的余数。

3. 移位操作符

了解移位操作符,首先必须了解一下权值是什么?原码、反码、补码又是什么,怎么得来的?下面一步步展开。

3.1 初步了解权值是什么

举一个例子就明白:

一个数字10用二进制表示为1010,所表示的意思是:10=1* 23 +0* 22 +1* 21+ 0*20.这里的1010的第一个1的权值就是23。第二个0的权值就是22。用八进制表示10,就是10=12,这里12中1的权值就是81,2的权值是80。下面我们再来了解原反补。

3.2 初步了解原码、反码、补码

一个数分为正数和负数,计算机中是不能识别负号的,所以计算机用补码的形式存储正数和负数,规定最高符号位对数分为正数和负数,正数最高符号位为0,负数为1,这样区分正数和负数。正数的原码、反码、补码都是一样的,负数的原码、反码、补码要进行运算(其中补码=反码+1,反码=原码按位取反(除了最高符号位)。

正数的最高符号位是0,负数的最高符号位是1。

举个例子:

正数10(因为是int类型的,所以有4个字节,也就是32个比特位)

00000000000000000000000000001010 - 10的原码

00000000000000000000000000001010 -10的反码

00000000000000000000000000001010 - 10的补码

正数的原码反码补码都相同

负数-10(32个比特位)

10000000000000000000000000001010 - -10的原码

11111111111111111111111111110101 - -10的反码

11111111111111111111111111110110 - -10的补码

负数的补码=反码+1,反码=原码按位取反(除了最高符号位不变)

3.3 左移操作符

移位规则:左边抛弃,右边补0。

先看现象,在分析:


a1ee0d9ed1d4cf0dd86a238f812befe5.png

分析:

10的补码(原码)是:

00000000000000000000000000001010

左移:

00000000000000000000000000010100 = 20(原码=补码)(因为是正数)

再来看一个奇怪的现象:

db2a6006fb27d3091e1c170a23a3a930.png

我们发现左移操作符可以对正数或者负数乘以2。

3.4 右移操作符

移位规则:右移运算分为两种:1.逻辑移位:左边用0填充,右边丢弃;2.算术移位:左边用原来该值的符号位填充,右边丢弃。其中编译器到底用哪一种呢?这是取决于编译器本身,绝大多数是用的算术移位。

还是一样先看现象再分析:

1e35fc1a674ca2d2fcb26262156dc296.png

10的补码(原码)是:

00000000000000000000000000001010

右移:

00000000000000000000000000000101 = 5(原码=补码)

再来看一个现象:

bd957e813e7b77124a86f8c20250e878.png

我们发现右移操作符可以对正数或者负数除以2。其中是取整方式是向0取整,不懂向取整可以点击文章开始的链接。

注意:对于移位操作符,不要移动负数位,这个是标准为定义。

这段话什么意思?看这个:


0bf968d2d665378e93adc91d38f5275a.png

4. 位操作符

& //按位与
| //按位或
^ //按位异或
注:他们的操作数必须是整数。

符号用法;

//&-按位与
//比特位同时为1时才为1
#include <stdio.h>
int main()
{
  int a = 10;
  //00000000000000000000000000001010(原反补相同)
  int b = -3;
  //10000000000000000000000000000011(原码)
  //11111111111111111111111111111100(反码)
  //11111111111111111111111111111101(补码)
  int c = a & b;
  //00000000000000000000000000001010(a)
  //11111111111111111111111111111101(b)
  //00000000000000000000000000001000=8(补码)(最高符号位是0,所以是正数,补码=原码)
  //
  printf("%d\n", c);
  return 0;
}
//|-按位或
//比特位同时为0时才为0
#include <stdio.h>
int main()
{
  int a = 5;
  //00000000000000000000000000000101 (5的原码也是补码)
  int b = -2;
  //10000000000000000000000000000010 (-2的原码)
  //11111111111111111111111111111101(-2的反码)
  //11111111111111111111111111111110(-2的补码)
  int c = a | b;
  //-2的补码|5的补码
  //11111111111111111111111111111111 (c的补码)
  //11111111111111111111111111111110(反码)
  //10000000000000000000000000000001=-1 (原码)
  printf("%d\n", c);
  return 0;
}
//按位异或
//比特位相同为0,不同为1
#include <stdio.h>
int main()
{
  int a = -8;
  //10000000000000000000000000001000 (-8的原码)
  //11111111111111111111111111110111(-8的反码)
  //11111111111111111111111111111000 (-8的补码)
  int b = 6;
  //00000000000000000000000000000110(6的原码,也是补码)
  int c = a ^ b;
  //-8的补码^6的补码
  //11111111111111111111111111111110(c的补码)
  //11111111111111111111111111111101(反码)
  //10000000000000000000000000000010=-2(原码)
  printf("%d\n", c);
  return 0;
}

4.1 练习:不能创建临时变量(第三个变量),实现两个数的交换

方法一(用按位异或来解决):

#include <stdio.h>
int main()
{
  int a = 10;
  //00000000000000000000000000001010(原码=补码)
  int b = 20;
  //00000000000000000000000000010100(原码=补码)
  a = a ^ b;
//a^b=00000000000000000000000000011110=30=a
  b = a ^ b;
  //b=0000000000000000000000011110(a)^b=00000000000000000000000000001010=10;
  a = a ^ b;
  //a=00000000000000000000000000011110(a)^00000000000000000000000000001010(b)=20(a)
  return 0;
}

方法二(用加法):

int main()
{
  int a = 3;
  int b = 5;
  int c = 0;
  c =a + b;//c=8
  a =c - a;//a=5
  b =c - a;//b=3
  return o;
}

4.2 练习:编写代码实现:求一个整数存储在内存中的二进制中1的个数

//方法一:
#include <stdio.h>
int main()
{
  int num = 10;
  int count = 0;//计数
  while (num)
  {
    if (num % 2 == 1)
      count++;
    num = num / 2;
  }
  printf("二进制中1的个数 = %d\n", count);
  return 0;
}
//方法二:
#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的个数 = %d\n", count);
  return 0;
}
 //方法三:
 #include <stdio.h>
int main()
{
  int num = 3;
  int i = 0;
  int count = 0;//计数
  while (num)
  {
    count++;
    num = num & (num - 1);
  }
  printf("二进制中1的个数 = %d\n", count);
  return 0;
}

5. 赋值操作符

这里再提一次:初始化和赋值的区别:初始化是创建变量的同时给定一个值,赋值时创建变量后对其给定一个值。

如:

#include <stdio.h>
int main()
{
    int a;
    a = 20;//这是赋值
    int b = 10;//这是初始化
    return 0;
}

5.1 连续赋值问题

#include <stdio.h>
int main()
{
  int a = 10;
  int b = 5;
  int c = 0;
  c = a = b + 8;
  printf("%d\n", c);
  return 0;
}//最终输出13
#include <stdio.h>
int main()
{
  int a = 10;
  int b = 5;
  int c = 0;
  a = b + 8;
  c = a;
  printf("%d\n", c);
  return 0;
}最终输出13

通过上述两段代码可以看出:

连续赋值的阅读体验极差,往往给人一种不想看的感觉。

5.2 复合赋值符

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

看一例子吧:

#include <stdio.h>
int main()
{
    int c = 0;
    c = c + 10;
   //c += 10;(相当于c = c + 10)
    return 0;
}



















相关文章
|
23天前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
|
23天前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
|
1月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
30 6
|
30天前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
42 0
十一:《初学C语言》—  操作符详解(上)
|
2月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
32 1
五:《初学C语言》—  操作符
|
3月前
|
C语言
C语言逻辑操作符的短路问题
C语言逻辑操作符的短路问题
|
3月前
|
编译器 C语言
【C语言】:中移位操作符,位操作符详运算规则详解
【C语言】:中移位操作符,位操作符详运算规则详解
27 1
|
3月前
|
算法 C语言
【C语言】:巧用移位操作符,位操作符解决问题
【C语言】:巧用移位操作符,位操作符解决问题
22 0
|
3月前
|
编译器 C语言
【C语言】:sizeof操作符的使用和各种常见数据类型的大小
【C语言】:sizeof操作符的使用和各种常见数据类型的大小
31 0
|
3月前
|
编译器 C语言 C++