C learning_12 操作符前篇(算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符)

简介: C learning_12 操作符前篇(算术操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符)

算术操作符


-- 加法操作符(+):用于将两个值相加。

-- 减法操作符(-):用于将两个值相减。

-- 乘法操作符(*):用于将两个值相乘。

-- 除法操作符(/):用于将两个值相除得到商。

-- 取余操作符(%):用于将两个值相除得到余数。



除法:

       1.整数除法(除号两边都是整数)

       2.浮点数除法(除号两边至少有一个小数)

       3.除数不能为零,除零报错(error C2124: 被零除或对零求模)


取余:m % n

       1.余数范围为【1,n-1】

       2.取余的操作数必须都是整数

       3. 不能对零取余,取余报错(error C2124: 被零除或对零求模)


移位操作符


-- 左移操作符(<<):将一个二进制数向左移动指定的位数,相当于该数乘以2的移动次幂

-- 右移操作符(>>):将一个二进制数向右移动指定的位数,相当于该数除以2的移动次幂


移位规则


左移

       左边抛弃、右边补0

右移


       1. 逻辑移位(逻辑移位是指将二进制数进行无符号移位)

               左边用0填充,右边丢弃

       2. 算术移位(算术移位是指将二进制数进行有符号移位)

               左边用原该值的符号位填充,右边丢弃


算术右移举例
#include<stdio.h>
int main()
{
  //整数在内存中存储的是补码
  signed int a = 15;
  //正数原、反、补码相同
  //原码:0000 0000 0000 0000 0000 0000 0000 1111
  //反码:0000 0000 0000 0000 0000 0000 0000 1111
  //补码:0000 0000 0000 0000 0000 0000 0000 1111
  signed int b = -15;
  //负数原、反、补不同
  //原码:1000 0000 0000 0000 0000 0000 0000 1111
  //反码:1111 1111 1111 1111 1111 1111 1111 0000
  //补码:1111 1111 1111 1111 1111 1111 1111 0001
  //a、b右移1位 - 移动的就是a、b的补码的二进制序列
  int c = a >> 1;
  //           [补]                                    [舍] 
  //移位后补码:0[0]000 0000 0000 0000 0000 0000 0000 111[1]
  //反码:      0 0 000 0000 0000 0000 0000 0000 0000 111
  //原码:      0 0 000 0000 0000 0000 0000 0000 0000 111 - 对应十进制 - 7
  int d = b >> 1;
  //           [补]                                    [舍] 
  //移位后补码:1[1]111 1111 1111 1111 1111 1111 1111 000[1]
  //反码:      1 1 111 1111 1111 1111 1111 1111 1110 111
  //原码:      1 0 000 0000 0000 0000 0000 0000 0001 000 - 对应十进制 - -8
  printf("%d\n", c);
  printf("%d\n", d);
  return 0;
}


注意:移位运算不会对原数据有任何的改变。


警告⚠ :

       对于移位运算符,不要移动负数位,这个是标准未定义的。

例如:

 int num = 10;

               num>>-1;//error


位操作符


-- 按位与操作符(&):将两个二进制数对应的位相与

-- 按位或操作符(|):将两个二进制数对应的位相或

-- 按位异或操作符(^):将两个二进制数对应的位异或

#include<stdio.h>
int main()
{
  int a = 3;
  //补码:0000 0000 0000 0000 0000 0000 0000 0011
  int b = -5;
  //原码:1000 0000 0000 0000 0000 0000 0000 0101
  //反码:1111 1111 1111 1111 1111 1111 1111 1010
  //补码:1111 1111 1111 1111 1111 1111 1111 1011
  //& - 对于的补码序列有0为0,全1为1
  printf("%d\n",a & b);
  //3 补码:0000 0000 0000 0000 0000 0000 0000 0011
  //-5补码:1111 1111 1111 1111 1111 1111 1111 1011
  //  &   :0000 0000 0000 0000 0000 0000 0000 0011 - 对应十进制 - 3
  //& - 对于的补码序列有1为1,全0为0
  printf("%d\n", a | b);
  //3 补码:0000 0000 0000 0000 0000 0000 0000 0011
  //-5补码:1111 1111 1111 1111 1111 1111 1111 1011
  //  |   :1111 1111 1111 1111 1111 1111 1111 1011 - 补码
  //       1000 0000 0000 0000 0000 0000 0000 0101 - 原码 - 对应十进制 - -5
  // ^ - 对于的补码序列不同为1,相同为0
  printf("%d\n", a ^ b);
  //3 补码:0000 0000 0000 0000 0000 0000 0000 0011
  //-5补码:1111 1111 1111 1111 1111 1111 1111 1011
  //  ^   :1111 1111 1111 1111 1111 1111 1111 1000 - 补码
  //       1000 0000 0000 0000 0000 0000 0000 1000 - 原码 - 对应十进制 - -8
  return 0;
}


交换两个整形变量的写法


#include<stdio.h>
int main()
{
  int a = 1;
  int b = 2;
  printf("交换前:a = %d,b = %d\n", a, b);
  int temp = 0;
  temp = a;
  a = b;
  b = temp;
  printf("交换后:a = %d,b = %d\n", a, b);
  return 0;
}


   这段代码展示了如何使用一个临时变量来交换两个变量的值。具体来说,代码中定义了两个整型变量a和b,并初始化为1和2。然后使用printf函数将它们的原始值打印出来。 接下来,代码定义了一个整型变量temp,并将a的值赋给temp,相当于把a的值复制到了temp中。然后,将b的值赋给a,相当于把b的值覆盖了a中原来的值。最后,将temp的值赋给b,相当于把a中原来的值存储到了b中。这样,a和b的值就互换了。 最后,代码使用printf函数再次将a和b的值打印出来,以显示它们已经被交换了。


 

#include<stdio.h>
int main()
{
  int a = 1;
  int b = 2;
  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;
}


 这段代码展示了一种不使用临时变量来交换两个变量的值的方法。具体来说,代码中定义了两个整型变量a和b,并初始化为1和2。然后使用printf函数将它们的原始值打印出来。


接下来,代码通过一系列的加减运算来交换a和b的值。首先将a和b的值相加,并将结果存储到a中。然后将新的a值减去旧的b值,并将结果存储到b中。最后将新a值减去刚才计算得到的新b的值,并将结果存储到a中。利用加减法运算完成了交换操作。最后,代码使用printf函数再次将a和b的值打印出来,以显示它们已经被交换了。注意,这种方法虽然不需要使用额外的变量来存储临时值,但需要进行多次加减运算,可能会影响代码的运行效率,同时由于是加法操作,会造成数据进行溢出。

#include<stdio.h>
int main()
{
  int a = 1;
  int b = 2;
  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;
}


  这也是一段C语言代码,同样实现了两个变量的值交换功能,但是它使用了异或运算(^)来完成交换操作。 具体地,首先定义了两个整型变量a和b,且分别赋值为1和2。然后输出交换前a和b的值。 接着,使用异或运算(^)按位进行交换,具体地,a先和b进行异或运算,然后将结果赋值给a。这时a变成了3(0011),同时由于异或运算支持交换律,所以此时b异或上a(即原来的a)就相当于b异或上新的a(即原来的a异或上原来的b),得到的结果赋值给b。这时b变成了1。最后再利用异或运算(^)完成a和b的值交换。 最后输出交换后a和b的值,即完成了值交换的操作。


赋值操作符


赋值操作符可以连续使用,

比如:


       int a = 10;

       int x = 0;

       int y = 20;

       a = x = y+1;//连续赋值


等价于:      


        int a = 10;

       int x = 0;

       int y = 20;

       x = y+1;

       a = x;


这样的写法是不是更加清晰,更加容易辨识。


复合赋值符:+=  -=  *=  /=  %=  >>=  <<=  &=  |=  ^=


单目操作符


单目操作符是一种只需要一个操作数的操作符,通常用于对单个变量或值进行操作。


sizeof和数组的纠缠


#include <stdio.h>
void test1(int arr[])
{
  printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
  printf("%d\n", sizeof(ch));
}
int main()
{
  int arr[10] = { 0 };
  char ch[10] = { 0 };
  printf("%d\n", sizeof(arr));
  printf("%d\n", sizeof(ch));
  test1(arr);
  test2(ch);
  return 0;
}


在主函数中,首先定义了一个大小为10的int类型和char类型的数组arr和ch,分别使用sizeof打印出数组大小。此时,打印结果应该是40和10,因为一个int类型的元素占用4个字节,而数组中共有10个元素,所以整个数组占用40个字节。而一个char类型的元素占用1个字节,而数组中共有10个元素,所以整个数组占用10个字节。 然后调用test1和test2函数,分别将arr和ch数组作为参数传递给函数。在函数调用中,实际上传递的是数组的指针,即数组的首元素的地址。因此,在函数内部使用sizeof操作符打印出的大小为指针的大小,即在32位系统中为4个字节,而在64位系统中为8个字节。


++和--运算符


//++和--运算符
#include <stdio.h>
int main()
{
    int a = 10;
    //前置++和--
    int x = ++a;
    //先对a进行自增,然后再使用a,也就是表达式的值是a自增之后的值。x为11
    int y = --a;
    //先对a进行自减,然后再使用a,也就是表达式的值是a自减之后的值。y为10
    //后置++和--
    int x = a++;
    //先对a先使用,再增加,这样x的值是10,之后a变成11
    int y = a--;
    //先对a先使用,再自减,这样y的值是11,之后a变成10
    return 0;
}


前置自增运算符“++”表示在使用变量之前先将变量的值加1,而后置自增运算符“++”表示先使用变量的值,然后再将变量的值加1。前置自减和后置自减运算符“--”也能使用相同的逻辑。


       在程序中,定义了一个整型变量a并初始化为10。接下来,使用前置自增运算符和前置自减运算符分别对变量a进行一次自增和自减操作,并将结果分别赋值给变量x和y。由于是前置运算符,因此表达式的值在使用变量之前就已经发生改变了,所以变量x和y的值分别为11和10。 接下来,再次使用变量a进行自增和自减操作,但这次使用的是后置自增“++”和后置自减“--”运算符。由于是后置运算符,表达式的值是先使用变量,然后再执行自增或自减操作,因此变量x和y的值分别为10和11,最后变量a的值变成了10。


       总结:前置自增和自减运算符在使用变量之前就对变量进行了加减操作,而后置自增和自减运算符在表达式的值确定之后才对变量进行加减操作。

#include<stdio.h>
int main()
{
  int a = 5;
  //0000 0000 0000 0000 0000 0000 0000 0101
  //0000 0000 0000 0000 0000 0000 0001 0000
  a |= (1 << 4);
  printf("%d\n", a);
  //0000 0000 0000 0000 0000 0000 0001 0101
  //1111 1111 1111 1111 1111 1111 1110 1111
  //0000 0000 0000 0000 0000 0000 0000 0101
  a &= (~(1 << 4));
  printf("%d\n", a);
  return 0;
}


多组输入的方案


#include<stdio.h>
int main()
{
  int n = 0;
  while (scanf("%d", &n) == 1)
  {
    printf("%d\n", n);
  }
  return 0;
}
#include<stdio.h>
int main()
{
  int n = 0;
  while (scanf("%d", &n) != EOF)
  {
    printf("%d\n", n);
  }
  return 0;
}
#include<stdio.h>
int main()
{
  //#define EOF    (-1)
  /*
    -1的补码
    1111 1111 1111 1111 1111 1111 1111 1111
    ~(-1)
    0000 0000 0000 0000 0000 0000 0000 0000
    while(0)为假就不执行了
  */
  int n = 0;
  while (~scanf("%d", &n))
  {
    printf("%d\n", n);
  }
  return 0;
}


关系操作符


>  >=  <  <=  !=  


注意:不可以比较字符串


逻辑操作符


&&     逻辑与

||        逻辑或

计算结果是真,用1表示;计算结果为假,用0表示。



小试牛刀

#include <stdio.h>
int main()
{
    int i = 0, j = 0 , a = 0, b = 2, c = 3, d = 4;
    i = a++ && ++b && d++;
    printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);//1 2 3 4
    i = 0, j = 0, a = 0, b = 2, c = 3, d = 4;
    j = a++ || ++b || d++;
    printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);//1 3 3 4
    return 0;
}


1.由于a++是后置++,所以a是先使用后自增,所以a++表达式是0,由于是逻辑与(&),并且逻辑与(&)具有短路的特点,只要有假就是假,后的表达式++b和d++都不会执行。


       所以结果是:1 2 3 4


2.由于a++是后置++,所以a是先使用后自增,所以a++表达式是0,由于是逻辑或(|),需要执行后面的表达式,由于++b是前置++,先自增后使用,++b的值为3,为真,并且逻辑或(&)具有短路的特点,只要一个为真就是着呢,后的表达式d++就不会执行。


       所以结果是:1 2 3 4


相关文章
|
存储 Oracle Java
JVM中Class文件结构详解
JVM中Class文件结构详解
225 0
|
关系型数据库 MySQL 数据安全/隐私保护
关于Navicat连接MySQL 报 Authentication plugin ‘caching_sha2_password‘ cannot be loaded
关于Navicat连接MySQL 报 Authentication plugin ‘caching_sha2_password‘ cannot be loaded
1072 2
|
9月前
|
Android开发 开发者 Python
通过标签清理微信好友:Python自动化脚本解析
微信已成为日常生活中的重要社交工具,但随着使用时间增长,好友列表可能变得臃肿。本文介绍了一个基于 Python 的自动化脚本,利用 `uiautomator2` 库,通过模拟用户操作实现根据标签批量清理微信好友的功能。脚本包括环境准备、类定义、方法实现等部分,详细解析了如何通过标签筛选并删除好友,适合需要批量管理微信好友的用户。
369 7
|
SQL API Python
`bandit`是一个Python静态代码分析工具,专注于查找常见的安全漏洞,如SQL注入、跨站脚本(XSS)等。
`bandit`是一个Python静态代码分析工具,专注于查找常见的安全漏洞,如SQL注入、跨站脚本(XSS)等。
|
10月前
|
存储 编解码 搜索推荐
如何在Windows和Mac上免费将蓝光转换为MKV?
蓝光光盘因能提供高质量的视频和音频内容而备受青睐,但其使用上的局限性却不容忽视。相比之下,MKV作为一种广受支持的视频格式,与大多数播放设备和平台都能完美兼容,为用户带来了更大的便利性和灵活性。
2050 0
|
11月前
|
JSON JavaScript 前端开发
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
392 0
一款简约单双页版HTML源码
开源的单页个人主页纯静态源码、目前有两个主页版本:master单页版、double双页版、非常漂亮的单页HTML源码
345 1
一款简约单双页版HTML源码
|
Java Nacos 数据安全/隐私保护
Nacos常见问题之无法工作如何解决
Nacos是一款易于使用的动态服务发现、配置管理和服务管理平台,针对不同版本可能出现的兼容性和功能问题,本汇总贴心整理了用户在使用Nacos时可能遇到的版本相关问题及答案,以便用户能够更顺畅地进行服务治理和配置管理。
1114 0
|
数据可视化 关系型数据库 MySQL
解决用软件登陆的Mysql8数据库时,报错:Authentication plugin ‘caching_sha2_password‘ cannot be loaded
解决用软件登陆的Mysql8数据库时,报错:Authentication plugin ‘caching_sha2_password‘ cannot be loaded
1301 0
解决用软件登陆的Mysql8数据库时,报错:Authentication plugin ‘caching_sha2_password‘ cannot be loaded