C语言操作符详解篇(全)

简介: C语言操作符详解篇(全)

前言


  • 我们在学习C语言时肯定会用到不同的操作符来完成我们的功能,本章便是这些操作符的介绍与具体使用。


1. 算数操作符


  • 算数操作符有四种,他们分别为:

  • 加 “+”,减 “-”,乘 “ * ”,除 “/”, 取模 “%
  • 值得注意的是,在C语言中乘号用 " * " 表示, 除号用 " / " 表示。
  • 取模号 " % " 求的是余数,比如 5除3余2 ,那么2便是计算的结果。
  • 通俗易懂,通过我们的数学知识很清楚的知道他们的作用。


int main()
{
  int a = 20;
  int b = 12;
  printf("a + b = %d\n", a + b);
  printf("a - b = %d\n", a - b);
  printf("a÷b = %d\n", a / b); // 这里20除12等于1,他不会显示后面的小数,除非计算式两边至少有一个浮点数
  printf("a×b = %d\n", a * b);
  printf("a % b = %d\n", a % b); // 这里20模12余数是8,结果便是8
  return 0;
}


5bee61b965c4487a8bf57e9f9403de7f.png


  • 值得注意的是,当计算式两边至少有一个浮点数的时候,相除才会计算出小数.


2.移位操作符


首先,我们来补充一个小知识:

  • 我们都知道,一个数在内存中是以二进制数来存放的,存放的是这个数的补码,那么什么是补码呢?
  • 一个数的二进制有原码,反码和补码,在计算中是用补码来计算的,而打印出来的是原码,这三个码之间有这样的关系,原码符号位不变,其它位按位取反得到反码,反码加一得到补码,而又补码要得到原码,反过来就是了.
  • 正数的原码反码补码相同,而负数则需要结果上面的计算来得到.
  • 由上可以得到,移位操作符,移位其实移的是在内存中储存的二进制数的补码.


2.1. 左移操作符

043b5a15ff6c4150b6cca460ef906ef8.png

(<<) : 补码左移,左边抛弃,右边补0.

#include <stdio.h>
int main()
{
  int a = 10;
  // a是一个整数所以他的原码,反码,补码相同
    // 原码:00000000000000000000000000001010
    // 反码:00000000000000000000000000001010
    // 补码:00000000000000000000000000001010
  int b = 15;
  int c = -5;
  // c为负数
  // 原码:10000000000000000000000000000101
  // 反码:11111111111111111111111111111010
  // 补码:11111111111111111111111111111011
  // 左移后:11111111111111111111111111110110 
  // 减一:11111111111111111111111111110101
  // 取反得到计算后的原码:10000000000000000000000000001010 - (-10)
  printf("%d\n", a << 1); // 左移1 // 00000000000000000000000000010100 - 20
  printf("%d\n", b << 1); // 左移1 // 00000000000000000000000000010100 - 30
  printf("%d\n", c << 1); // 左移1
  // 补码左移 右边补 0
  // 00000000000000000000000000010100 - 20
  return 0;
}


043b5a15ff6c4150b6cca460ef906ef8.png

  • 不难看出,左移操作符具有乘以 2 的效果.


2.2. 右移操作符


(>>):右移操作符与左移操作符计算过程几乎相同,有一点不同的是,右移操作符分为算数右移和逻辑右移:

  • 算数右移: 左边补符号位,右边抛弃.
  • 逻辑右移: 左边补0,右边抛弃.
  • 通常来说进行右移时是逻辑右移.
#include <stdio.h>
int main()
{
  int a = 10;
  int b = -5;
  printf("%d\n", a >> 1); // 5
  printf("%d\n", b >> 1); // -3
  // b计算过程
  // 原码:10000000000000000000000000000101
  // 反码:11111111111111111111111111111010
  // 补码:11111111111111111111111111111011
  // 右移:11111111111111111111111111111101
  // 减一:11111111111111111111111111111100
  // 取反:10000000000000000000000000000011
  // 右移1后的数为 10000000000000000000000000000011 - (-3)
  return 0;
}

e190b7137b024582ac84b8d5ce5b0b3b.png


无论是左移还是右移,我们都不能移动负数为,如: a >> -1.


3.位操作符


同样的,位操作符也是对补码进行计算


3.1 &


  • 按位与是 : 如果两个二进制补码相同位数上有一个为零则为0,都为1则为1.
#include <stdio.h>
int main()
{
  int a = -5;
  // 原:10000000000000000000000000000101
  // 反:11111111111111111111111111111010
  // 补:11111111111111111111111111111011
  int b = 3;
  // 原:00000000000000000000000000000011
  // 补:00000000000000000000000000000011
  // a & b
  // 补:11111111111111111111111111111011
  // 补:00000000000000000000000000000011
  // 有一个0则为0,都为1则1
  // 得:00000000000000000000000000000011
  // 为整数:3
  printf("%d", a & b);
  return 0;
}


35b777eb95be4c8cb71b57e93e380d8f.png

3.2 |


  • 按位或是 : 如果两个二进制补码相同位数上只要有一个为1则为1,全0则0.
#include <stdio.h>
int main()
{
  int a = 10;
  // 补:00000000000000000000000000001010
  int b = -2;
  // 原:10000000000000000000000000000010
  // 反:11111111111111111111111111111101
  // 补:11111111111111111111111111111110
  // a | b
  // 00000000000000000000000000001010 
  // 11111111111111111111111111111110
  // 11111111111111111111111111111110 结果
  // 减一:11111111111111111111111111111101
  // 取反:10000000000000000000000000000010 (-2)
  printf("%d", a | b); // -2
  return 0;
}


5f1bb24690fe42d7a19808024fefc72a.png


3.3 ^

  • 按位异或是:相同为0,相异为1.
#include <stdio.h>
int main()
{
  int a = 3;
  // 补:00000000000000000000000000000011
  int b = 5;
  // 补:00000000000000000000000000000101
  // a ^ b
  // 00000000000000000000000000000011
  // 00000000000000000000000000000101
  // 00000000000000000000000000000110 - 6
  printf("%d\n", a ^ b); // 6
  printf("%d\n", a ^ 0); // a
  printf("%d\n", b ^ 0); // b
  printf("%d\n", a ^ a); // 0
  return 0;
}



8dbfaf1743ca4545a429deb2bb78df72.png


  • 值得注意的是:
  • a ^ 0 = a;
  • b ^ 0 = b;
  • a ^ a = 0;
  • 那么可以得到:
  • a ^ a ^ b = b;
  • b ^ b ^ a = a;

有一道经典题目:不创建临时变量交换两个变量的值。我们便可以用上述推理来实现


#include <stdio.h>
int main()
{![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/82c60be1cb6f4fc0b0a5b41971123922.png#pic_center)
  int a = 3;
  int b = 5;
  printf("交换前:%d %d\n", a, b);
  a = a ^ b;
  b = a ^ b;
  a = a ^ b;
  printf("交换后:%d %d\n", a, b);
  return 0;
}



6fa90e9b5d764ce993c6dccf7fbc5d9d.png


3.4 ~

按位取反是补码二进制位如果是1则变为0,如果是0则变为1。

#include <stdio.h>
int main()
{
  int a = 3;
  // 补:00000000000000000000000000000011
  // 反:11111111111111111111111111111100  补码变负
  // -1:11111111111111111111111111111011
  // 原:10000000000000000000000000000100  -4
  printf("%d", ~a);
  return 0;
}


e207382729da4202a2da3264012db71f.png


4.赋值操作符

  • =
    例如:a = 5,这里将5赋值给变量a
  • 复合型:
  • +=
  • -=
  • /=
  • *=
  • %=
  • &=
  • |=
  • ^=
  • (<<=)
  • (>>=)
    例如:a+=2其实就是a=a+2,其他的复合型都是如此


5.单目操作符

  -            负值
  +            正值
  ++           a++:后置加加  ; ++a:前置加加(都是a+=1)
  --           与++效果相同
  !            逻辑反操作
  &            取地址符号
  ~            二进制数按位取反
  *            解引用操作
  sizeof       求类型长度(以字节为单位)
  (类型)        强制类型转换


这里对++和!作讲解

++

首先看代码:

#include <stdio.h>
int main()
{
  int a = 1;
  int b = a++; // 先把a的值赋给b,a再自增1
  int c = ++a; // a先自增1,再赋值给c
  printf("%d\n", a); // 3
  printf("%d\n", b); // 1
  printf("%d\n", c); // 3
  return 0;
}


前置加加和后置加加其实在上述代码里其实效果很明显了,只要我们用一次++,其对应变量就要自增1。–与++的运用效果是相同的,只不过说是自减1。

!:!= 就是不等于,其相当于非。!0 就是真,!1就是假。


6.关系操作符


  • (>)
  • (>=)
  • (<)
  • (<=)
  • (!=)
  • (==)


上述操作符多用在判断语句中,用来决定程序进程变化。


7.逻辑操作符

&&

逻辑与:如 a&&b ,当a,b都为真时,表达式为真,当其中有一个为假时为假

#include <stdio.h>
int main()
{
  int a = 0;
  int b = 1;
  int c = 2;
  int d = 3;
  int i = a++ && ++b && c++; // a++表达式结果为a的值,此时a=0,由&&的性质有一个为假就为假,则后面都不计算了
    //但是a++还是要进行计算的,也就是a要自增1
  printf("%d %d %d %d\n", a, b, c, d);
    // 结果为 1 1 2 3
  return 0;
}


||

逻辑或:如 a || b,当a,b中只要有一个为真,表达式为真,都为假表达式才为假

#include <stdio.h>
int main()
{
  int a = 1;
  int b = 2;
  int c = 3;
  int d = 4;
  int i = a++ || b++ || ++d || c--; // a++表达式结果为a,此时a=1为真,由||性质,整个表达式结果为真,则后面的不计算了
  // a++还是要计算的,也就是a要自增1
  printf("%d %d %d %d\n", a, b, c, d);
  // 结果为 2 2 3 4
  return 0;
}


结合

我们可以通过判断闰年这个经典的题目来熟悉掌握&& ||。

#include <stdio.h>
int main()
{
  int n = 0;
  scanf("%d", &n);
  if (((n % 4 == 0) && (n % 100 != 0)) || (n % 400 == 0))
  {
    printf("%d年是闰年!\n", n);
  }
  else
  {
    printf("%d不是闰年!\n", n);
  }
  return 0;
}


8.条件操作符


exp1 ? exp2:exp3;

  • 如果 exp1 为真,表达式结果为 exp2
  • 如果 exp1 为假,表达式结果为 exp3

例如求两个变量的最大值:

#include <stdio.h>
int main()
{
  int a = 0;
  int b = 0;
  scanf("%d %d", &a, &b);
  printf("max = %d\n", (a > b ? a : b));
  return 0;
}


9.逗号表达式

  • 优先级最低
  • 用逗号隔开多个表达式
  • 整个表达式由左向右依次计算,计算结果为最后一个表达式的结果
#include <stdio.h>
int main()
{
  int a = 1;
  int b = 2;
  int c = (a += 2, b = b + 1, a += 1, a / 2);
  printf("%d", c); // 2
  return 0;
}


我们可以看到从左向右依次计算,最后a = 4,4 / 2 = 2,所以最后c的值为2;


10.表达式求值

10.1.隐式类型转换


CPU在进行运算的时候一般使用整形int,所以在有些时候,当一个小于整形的类型进行计算时,计算机就会先进行整形提升再进行运算,这就是隐式类型转换。


(通用CPU是难以直接实现两个非整形的直接相加运算)

例:

// char short int long ...
//  1     2    4
int main()
{
  //char --> signed char
  char a = 3;
  //截断
  //00000000000000000000000000000011
  //00000011 - a
  //
  char b = 127;
  //00000000000000000000000001111111
  //01111111 - b
  char c = a + b;
  //00000011
  //01111111
  //整型提升
  //00000000000000000000000000000011 - a
  //00000000000000000000000001111111 - b
  //00000000000000000000000010000010 - a + b =c
  //截断
  //10000010 - c
  printf("%d\n", c);
  //%d 是打印十进制的整数
  //11111111111111111111111110000010 - 补码
  //11111111111111111111111110000001 - 反码
  //10000000000000000000000001111110 - 原码
  //-126
  return 0;
  }


输出结果:

输出:-126

注:

char:

有符号的char的取值范围是:-128~127

无符号的char的取值范围是:0~255

  • 以上是一位大佬的讲解(写的很详细),这里直接引用他的,大家可以多看看他的博客,一定会有很大的帮助的。
    ——@戊子仲秋


10.2.算数转换


long double:最高

double

float unsigned long int

long int

unsigned int

int


  • 当我们再利用两个不同类型的变量来进行计算时,其算数级低的会自动升级到算数级高的类型去进行计算,如果进行一些不正当的算数转换,会导致数据丢失。

如:

#include <stdio.h>
int main()
{
  float e = 2.717f;
  int w = e;
  printf("%d", w);
  return 0;
}


运行结果为:

输出: 2

可以看到,e值小数点后面的数丢失了,这是由高级到低级转换的结果(不能用)


11.操作符的准确使用


  • 操作符之间有其对应的优先级,当我们进行运算时,优先比较相邻两个操作符的优先级,如果一个表达式很复杂,简易用()来分明其运算顺序,不然在不同的编译器上可能会有不同的运算结果。


总结


C语言中操作符的使用可以说是司空见惯的,如何正确的使用是我们必须掌握的,学到后面,我们可以尝试着巧妙运用操作符去解决一些复杂的问题,这需要我们不断地练习与巩固。在此,感谢大家的阅读!



相关文章
|
3月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
74 0
|
3月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
255 0
|
26天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
34 10
|
1月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
160 1
|
1月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
171 0
|
3月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
45 6
|
3月前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
59 0
十一:《初学C语言》—  操作符详解(上)
|
4月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
44 1
五:《初学C语言》—  操作符
|
5月前
|
C语言
C语言逻辑操作符的短路问题
C语言逻辑操作符的短路问题
|
5月前
|
编译器 C语言
【C语言】:中移位操作符,位操作符详运算规则详解
【C语言】:中移位操作符,位操作符详运算规则详解
44 1