C语言操作符(上)(一)

简介: C语言操作符(上)

1. 操作符的分类


操作符


操作符的分类想必大家都知道,这里就不赘述了。本文只是介绍其中的一部分操作符。


2. 算术操作符


算术操作符主要有:


+ - * / %


其中除法(/)分为两类:


  1. 只含整数的除法:运算结果为整数
  2. 含有浮点数的除法:运算结果为浮点数


注意:%(取模)的结果是余数。并且取模操作符的两个操作数必须都是整数!


3. 移位操作符


<< 左移操作符


>>右移操作符


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


【右移】:


补充:整数的二进制表示形式有三种:原码,反码,补码。


  1. 正数的原码反码补码相同。
  2. 负数的原码反码补码要进行计算,不能直接判断。


原码反码补码的计算方法:一个整数,无论正负,直接将其翻译为二进制序列,该二进制序列就是原码。


int a = 15 ;


因为15是被存放在int型中的,而int型有32个比特位,其最高位表示符号位,将其翻译成二进制位就是:


00000000000000000000000000001111  //(最高位是0,表示该数为正数)


就得到了a的原码。因为a是15,为正数,所以该原码同时也是a的反码和补码。


int b = -15;


接下来我们将b翻译成二进制序列:


10000000000000000000000000001111  //原码    (最高位是1,表示该数是负数)
11111111111111111111111111110000  //反码    符号位不变,其他位按位取反得到b的反码
11111111111111111111111111110001  //补码    反码+1得到补码


该二进制序列是b的原码,由于b是负数,所以其反码和补码要根据上面的规则进行计算。


注意:数据在内存中是以补码的形式进行存储的。


那么移位操作就是对数据的补码进行操作的。例如:


int a = 15;
00000000000000000000000000001111  //a的原码 同时也是反码和补码,这里我们将其看作补码
int b = a >> 1; //将a右移一位
00000000000000000000000000000111  //a右移之后得到的二进制序列,得到的是补码,但其是正数,所以其原反补相同
printf("%d",b);  //打印7
printf("%d",a);  //a的值不变,还是15


注意:C语言中的右移操作分位两种:(一般编译器采用的是算术右移)


  • 算术右移(右边丢弃,最高位补原来的符号位)
  • 逻辑右移(有边丢弃,最高位一律补0)


在内存中存放的是补码,那么操作之后得到的结果也应该是补码,所以我们要想知道操作的值是多少,必须将操作结果转换成原码,这里看到代码第4行,其最高位是0,代表运算结果是负数,所以其原码反码补码相同。所以直接将该二进制序列的值赋值给b变量,b变量的值就是a右移两位的结果。


接下来在讲一个负数右移:


int main()
{
  int a = -15;
  10000000000000000000000000001111    //a的原码
    11111111111111111111111111110000  //原码除了符号位不变,其他按位取反得到反码。
    11111111111111111111111111110001  //反码+1得到补码
  int b = a >> 1;
    11111111111111111111111111111000  //右移一位,最高位补符号位,也就是补1,得到补码
    11111111111111111111111111110111  //除了符号位之外,其他按位取反,得到反码
    10000000000000000000000000001000  //反码+1,得到原码,翻译成10进制,也就是-8
  printf("%d\n", b);//打印 -8
  printf("%d\n", a);//打印 15
  return 0;
}


得到操作结果之后,再将该结果转换为其原码,再翻译为十进制,就是-8。所以执行结果是打印-8


【左移】:左移就是将数据的补码向左移动,左边被移出的数据直接丢弃,右边补0。得到的操作结果仍然位补码,需要将其转换成原码。举个例子:


int main()
{
  int a = 15;
  00000000000000000000000000001111    //a的原码,a为正数,原反补相同
  int b = a << 1;
    00000000000000000000000000011110  //左移一位得到补码,由符号位可知,该二进制序列为正数,原反补相同
  printf("%d ", b);//打印30
  printf("%d ", a);//打印15
  return 0;
}


特别注意:移位操作不能移动负数位,例如:


int a = 15 >> -1;


这种操作是错误的,是C语言标准未定义的。


4. 位操作符


这里要先知道位操作符都是针对数据的二进制补码进行运算的,所以位操作符的操作数必须是整数。


【分类】


  • &(按位与)
  • |(按位或)
  • ^(按位异或)


【按位与】


运算规则:二进制位有0则为0,全是1才为1。例如:


int main()
{
  int a = 2;
  //00000000000000000000000000000010
  int b = 1;
  //00000000000000000000000000000001
  int c = a & b;
  //00000000000000000000000000000000
  printf("%d ", c); //打印0
  return 0;
}


这里分别写出a和b的二进制补码,将其进行按位与操作,得到全0的二进制序列,结果也就是0。


【按位或】


运算规则:二进制位有1则为1,全为0才是0。例如:


int main()
{
  int a = 2;
  //00000000000000000000000000000010
  int b = 1;
  //00000000000000000000000000000001
  int c = a | b;
  //00000000000000000000000000000011
  printf("%d ", c); //打印3
  return 0;
}


分别写出a和b的二进制补码,将其进行按位或操作,得到的二进制序列翻译成10进制也就是3。


【按位异或】


运算规则:二进制位相同为0,相异为1。例如:


int main()
{
  int a = 5;
  //00000000000000000000000000000101
  int b = 1;
  //00000000000000000000000000000001
  int c = a ^ b;
  //00000000000000000000000000000100
  printf("%d ", c); //打印4
  return 0;
}


分别写出a和b的二进制补码,将其进行按位异或操作,得到的二进制序列就是4。


【按位异或的性质】


  1. 一个数和0异或得到的结果仍是其本身:我们将一个整数a和0进行异或操作,得到的一定是a本身。
  2. 两个相同的数异或得到的结果一定是0。
  3. 异或运算满足交换律和结合律。


【按位异或的应用】


Q1:如何交换两个整数?


交换两个整数的值可以有三种方法:


【Answer1】:


int main()
{
  int a = 10;
  int b = 20;
  printf("before: a = %d b = %d\n", a, b);
  int tmp = a;
  a = b;
  b = tmp;
  printf("after : a = %d b = %d\n", a, b);
  return 0;
}


这种方法会创建新的变量,但是总体问题不大。


【Answere2】:


int main()
{
  int a = 10;
  int b = 20;
  printf("before: a = %d b = %d\n", a, b);
  a = a + b;
  b = a - b;
  a = a - b;
  printf("after : a = %d b = %d\n", a, b);
  return 0;
}

这种方法有个弊端:当a和b的值很大时,将其加在一起可能就会超过int数据类型所能存储的最大数据范围。


【Answer3】:


int main()
{
  int a = 10;
  int b = 20;
  printf("before: a = %d b = %d\n", a, b);
  a = a ^ b;
  b = a ^ b;
  a = a ^ b;
  printf("after : a = %d b = %d\n", a, b);
  return 0;
}


这种方法就比较巧妙了。


1fbf95a6de9336b0fb2424cd1a7413b7_0d23c2e5385842dc8a694866efb4e620.png


这里要结合异或运算的性质进行分析。


【位操作符的应用】


Q2:求一个整数存储在内存中的二进制中1的个数。


【Answer1】:


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;
}


首先强调:**该方法只适用于正数!**该方法先判断该非0数是不是奇数,若是奇数,其最低的二进制位必定是1,计数器加1。接着再将该数除以2,(这里要注意,将一个正整数除以2,等效于将其二进制序列右移一位),再通判断该数的奇偶性间接判断其二进制位的最低位是否为1。知道num为0则停止。


该方法的缺陷是只适用于正整数。


【Answer2】:


我们首先知道,1与0进行按位与操作得到的是0,1与1按位与操作得到的1。


所以可以将该整数的二进制位的最低位和1进行按位与操作,其他高位与0进行按位与操作。此时整个表达式的执行结果就只与该整数的最低二进制位有关了,若最低二进制位是1,则结果为1,若最低二进制位为0,则结果为0。将该最低二进制位判断完毕之后,将整个二进制序列右移1位。将该操作进行32次,因为一个int类型的数据占用32个二进制位,我们需要将每一位都判断一次。


int main()
{
    int num = -1;
    int i = 0;
    int a = 1;
    int count = 0;//计数
    for (i = 0; i < 32; i++)
    {
        if (num & a)
            count++;
        num >>= 1;
    }
    printf("二进制中1的个数 = %d\n", count);
    return 0;
}


【Answer3】:


int main()
{
     int num = 9;
     int i = 0;
     int count = 0;//计数
     while(num)
     {
         count++;
         num = num&(num-1);
         //第一次执行该语句时:
         //00000000000000000000000000001001
         //00000000000000000000000000001000
         //00000000000000000000000000001000
     }
     printf("二进制中1的个数 = %d\n",count);
     return 0;
}


这种方法难以想到。每执行一次num = num&(num-1);语句都能除去二进制序列中权值位最小的1。


相关文章
|
19天前
|
存储 网络协议 C语言
【C语言】位操作符详解 - 《开心消消乐》
位操作符用于在位级别上进行操作。C语言提供了一组位操作符,允许你直接操作整数类型的二进制表示。这些操作符可以有效地处理标志、掩码、位字段等低级编程任务。
65 8
|
19天前
|
C语言
【C语言】逻辑操作符详解 - 《真假美猴王 ! 》
C语言中有三种主要的逻辑运算符:逻辑与(`&&`)、逻辑或(`||`)和逻辑非(`!`)。这些运算符用于执行布尔逻辑运算。
62 7
|
4月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
87 0
|
4月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
292 0
|
2月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
48 10
|
2月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
184 1
|
2月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
187 0
|
4月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
46 6
|
4月前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
63 0
十一:《初学C语言》—  操作符详解(上)
|
5月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
46 1
五:《初学C语言》—  操作符