【万字讲解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;
}
相关文章
|
3月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
74 0
|
3月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
257 0
|
27天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
34 10
|
1月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
160 1
|
1月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
172 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语言】:巧用移位操作符,位操作符解决问题
35 0