C语言-操作符详解(5)

简介: C语言-操作符详解(5)

1. 操作符分类:

思维导图:


2. 算术操作符

+     -     *     /     %

#include 
int main()
{
  int a = 10 / 3;//除法操作符,两边都是整数就执行整数除法
  printf("%d\n", a);
  double b = 10.0 / 3;//两边只要有一个是浮点数就能计算出小数
  printf("%lf\n", b);
  printf("%.1lf\n", b);//在lf前面加.1能保留小数点后一位,.几就保留几位
  return 0;
}

输出结果:


输出:

3

3.333333

3.3

#include 
int main()
{
  int ret = 10 % 3;//取模,操作符两边必须是整数
  printf("%d\n,ret");
  return 0;
}

输出结果:


输出:1

3. 移位操作符

在讲移位前,需要知道一些基本的概念:


二进制:


二进制整数有三种表示形式:


1. 原码


2. 反码


3. 补码


而在内存中存储的是:二进制的补码


所以参数在移位时是二进的补码。


例:


int main()
{
  //整形类型占四个字节(32个比特位),二进制的表现形式:
  int a = 10;
  //00000000000000000000000000001010 - 原码
  //00000000000000000000000000001010 - 反码
  //00000000000000000000000000001010 - 补码
  int a = -10;
  //10000000000000000000000000001010 - 原码
  //11111111111111111111111111110101 - 反码
  //11111111111111111111111111110110 - 补码
  return 0;
}


通过观察发现正数原码、反码、补码相同,


负数反码是:原码符号位不变,其它位按位取反,补码是:反码+1。


3.1 左移操作符

例:


#include 
int main()
{
  //左移操作符:<<
  //规则:左边抛弃,右边补零
  int a = 10;
  //a:
  //00000000000000000000000000001010 - 补码
  int b = a << 1;
  //b:
  //00000000000000000000000000010100 - 补码
  printf("%d\n", b);
  int c = -10;
  //c:
  //10000000000000000000000000001010 - 原码
  //11111111111111111111111111110101 - 反码
  //11111111111111111111111111110110 - 补码
  int d = c << 1;
  //d:
  //11111111111111111111111111101100 - 补码
  //11111111111111111111111111101011 - 反码
  //10000000000000000000000000010100 - 原码
  printf("%d\n", d);
  return 0;
}


(注:printf 打印出来给我们看的是原码。)


输出结果:


输出:

20

-20

总结:


左移操作也可以看成是乘二的操作。


3.2 右移操作符

例:


#include 
int main()
{
  //右移操作符:>>
  //1.算数右移:左边补符号位,右边抛弃(常用)
  //2.逻辑右移:左边补零,右边抛弃
  int a = 10;
  //a:
  //00000000000000000000000000001010 - 补码
  int b = a >> 1;
  //b:
  //00000000000000000000000000000101 - 补码
  printf("%d\n", b);
  int c = -10;
  //c:
  //10000000000000000000000000001010 - 原码
  //11111111111111111111111111110101 - 反码
  //11111111111111111111111111110110 - 补码
  int d = c >> 1;
  //d:
  //11111111111111111111111111111011 - 补码
  //11111111111111111111111111111010 - 反码
  //10000000000000000000000000000101 - 原码
  printf("%d\n", d);
  return 0;
}

输出结果:


输出:

5

-5

注:无论是右移还是左移的位数都不能为负数。


例:


ret>>-1

这样写是错误的

4. 位操作符

&   按位与


|     按位或


^    按位异或


4.1 &

例:


#include 
int main()
{
  //& - 按二进制与
  //规则:有零则零
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码
  int c = a & b;
  //00000000000000000000000000000011 - a 补码
  //11111111111111111111111111111011 - b 补码
  //00000000000000000000000000000011 - c 原码
  printf("%d\n", c);
  return 0;
}


输出结果:


输出:3

4.2 |

例:


#include 
int main()
{
  // | - 按二进制位或
  // 规则:有一则一
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码
  int c = a | b;
  //00000000000000000000000000000011 - a补码
  //11111111111111111111111111111011 - b补码
  //11111111111111111111111111111011 - c补码
    //11111111111111111111111111111010 - c反码
    //10000000000000000000000000000101 - c原码
  printf("%d\n", c);
  return 0;
}


输出结果:


输出:-5

4.3 ^

例:


#include 
int main()
{
  // ^ - 按二进制位异或
  // 规则:相同为零,相异为一
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码
  int c = a ^ b;
  //00000000000000000000000000000011 - a补码
  //11111111111111111111111111111011 - b补码
  //11111111111111111111111111111000 - c补码
  //11111111111111111111111111110111 - c反码
  //10000000000000000000000000001000 - c原码
  printf("%d\n", c);
  return 0;
}


输出结果:


输出:-8

练习:


一道编程题:


如何不创建临时变量完成两个数的交换


例:


#include 
int main()
{
  int a = 3;
  int b = 5;
  printf("%d %d\n", a, b);
  a = a ^ b;
  b = a ^ b;// b = a ^ b ^ b  // 而 a ^ b ^ b = a 所以b就赋值为a
  a = a ^ b;// a = a ^ b ^ a  // 而 a ^ b ^ a = b 所以a就赋值为b
  printf("%d %d\n", a, b);
  return 0;
}

输出结果:


输出:

3 5

5 3

用异或操作符交换两个变量的弊端:


1. 可读性差


2. 效率没有创建临时变量高


3. 异或只能用于整数变量的交换


总结:这种方法了解即可,平时使用临时变量交换两个变量的方法更好。


5. 赋值操作符

赋值操作符能给变量赋值。


例:


int main()
{
  int a = 10;
  a = 100;// = 能将a赋值成100
  return 0;
}

还有复合赋值符:


例:


+=    


-=      


*=      


/=      


%=


>>=    


<<=    


&=      


|=    


^=


这些运算符都可以写成复合的效果(规则都是一样的)


例:


int main()
{
  int a = 10;
  a += 10;//这个其实就是:a = a + 10
  printf("%d\n", a);//输出的结果就是20
  return 0;  
}

6. 单目操作符

!              逻辑反操作


-              负值


+             正值


&             取地址


sizeof      操作数的类型长度(以字节为单位)


~             对一个数的二进制按位取反


--            前置、后置--


+            前置、后置++


*             间接访问操作符(解引用操作符)


(类型)     强制类型转换


6.1 单目操作符介绍

例1:


#include 
int main()
{
    //! 逻辑反操作
  //C语言中0表示假,非零表示真
  int n = 0;
  if (n)
  {
  printf("1\n");
  }
  if (!n)//!逻辑反操作,将假变为真(也能从真变假)
  {
  printf("2\n");
  }
  return 0;
}


输出结果:


输出:2

例2:

#include 
int main()
{    // + -
  int a = -10;
  printf("%d\n", a);
  printf("%d\n", -a);
  printf("%d\n", +a);//‘+’几乎没有用处
  return 0;
}


输出结果:


输出:

-10

10

-10

例3:


#include 
int main()
{
  // ~ 按位取反
  //00000000000000000000000000000000
  //11111111111111111111111111111111 - 补码是全1
  int a = 0;
  printf("%d\n", ~a);

}

输出结果:


输出:-1

例4:


#include 
int main()
{
    //++
  int a = 10;
  int b = a++;//后置++,先使用,再++
  printf("%d\n", b);
  printf("%d\n", a);
  int c = 10;
  int d = ++c;//前置++,先++,再使用
  printf("%d\n", d);
  printf("%d\n", c);
  return 0;
}


输出结果:


输出:

10

11

11

11

注:-- 的规则与 ++ 是一样的。


#include 
int main()
{
  // ++ -- 是带有副作用的
    // 会改变变量自身的值 
  //1
  int a = 10;
  int b = ++a;//b=11 a=11
  //2
  int a = 10;
  int b = a + 1;//b=11 a=10
  return 0;
}

例5:


#include 
int main()
{ // (类型)强制类型转换
  int a = (int)3.14;//这样编译器就不会报警告
  srand((unsigned int)time(NULL));//将类型为time_t的time转成srand需要的无符号整形
  return 0;
}

6.2 sizeof 和数组

例:


#include 
void test1(int arr[])//本质上传过来的是数组首元素的地址
{
  printf("%d\n", sizeof(arr));//地址在32位环境占4个字节
}                                //在64位的环境中占8个字节
void test2(char ch[])
{
  printf("%d\n", sizeof(ch));//我是32位的环境,所以输出4
}
int main()
{
  int arr[10] = { 0 };
  char ch[10] = { 0 };
  printf("%d\n", sizeof(arr));//int类型占4个字节
  printf("%d\n", sizeof(ch));//char类型占1个字节
  test1(arr);
  test2(ch);
  return 0;
}


输出结果:


输出:

40

10

4

4

7. 关系操作符

>


>=


<


<=


!=       用于测试“不相等”


==      用于测试“相等”


注:别把 “==” 和 “=” 给写错了。


8. 逻辑操作符

&&     逻辑与  ( a&&b    a,b都要满足才真)


||       逻辑或  (   a||b     a,b只要满足一个就真)


例:


输出结果:


输出:

a = 1

b = 2

c = 3

d = 4

#include 
int main()
{
  int i = 0, a = 1, b = 2, c = 3, d = 4;
  i = a++ || ++b || d++;
  //(a++)这个表达式为真,那||左边就无须计算了
  //所以(++b)(d++)都不计算了
  printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
  return 0;
}

输出结果:


输出:

a = 2

b = 2

c = 3

d = 4

9. 条件操作符

exp1 ? exp2 : exp3


例:


这是一个求较大值的代码:


#include 
int max(int a, int b)
{
  if (a > b)
  return a;
  else
  return b;
}
int main()
{
  int a = 10;
  int b = 20;
  printf("%d\n", max(a, b));
  return 0;
}

输出结果:


输出:20

而用条件操作符:


#include 
int max(int a, int b)
{
  return (a > b ? a : b);//如果a>b则取a,否则取b
}
int main()
{
  int a = 10;
  int b = 20;
  printf("%d\n", max(a, b));
  return 0;
}

输出结果:


输出:20

两种写法是一模一样的。


10. 逗号表达式

逗号表达式:


1. 用逗号隔开的多个表达式。


2. 从左向右依次执行。整个表达式的结果是最后一个表达式的结果。


例:


#include 
int main()
{
  int a = 1;
  int b = 2;
  int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
  //先算a = b + 10,算出a = 12,再算b = a + 1,算出b = 13,
  //最后结果就是最后一个表达式(b = a + 1)的值
  printf("c = %d\n", c);
  return 0;
}

输出结果:


输出:13

11. 结构成员

结构体在C语言中一般用于描述复杂对象,比如人、书,C语言中没有这样的类型,


但是结构体能让我们创建新的类型。



12. 表达式求值

12.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


12.2 算术转换

不同操作类型的数进行运算时会进行算数转换:


long double

double

float unsigned long int

long int

unsigned int

int


注:算数转换不合理会产生一些问题:


#include
int main()
{
  float f = 3.14;
  int num = f;//隐式转换,会有精度丢失
  printf("%d\n", num);
  return 0;
}

输出结果:


输出:3

12.3 操作符的属性

复杂表达式的求值有三个影响的因素:


1. 操作符的优先级


2. 操作符的结合性


3. 是否控制求值顺序


但是,我们写出的代码如果没有唯一的运算路径,就会出问题


所以,总结:平时写代码的运算路径要唯一。


写在最后

以上就是本篇文章的内容了,感谢你的阅读。


如果喜欢本文的话,欢迎点赞和评论,写下你的见解。


如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。



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