五、操作符复习

您所在的位置:网站首页 浮点数的用法 五、操作符复习

五、操作符复习

2023-06-11 19:26| 来源: 网络整理| 查看: 265

目录

一、算术操作符

0x00 概览

0x01 整数除法

0x02 浮点数除法

0x03 取模操作符

0x04 整除和浮点除的区分

二、移位操作符

0x00 概览

0x01 左移操作符

0x02 右移操作符

0x03 整数的二进制表示方式(初步了解)

三、位操作符

0x00 概览

0x01 按位与 &

0x02 按位或

0x03 按位异或 ^

0x04 位操作符的应用

四、赋值操作符

0x00 概览

0x01 一般赋值

0x02 连续赋值

0x03 复合赋值符

五、单目操作符

0x00 概览

0x01 逻辑反操作 !

0x02 负值 -

0x03 正值 +

0x04 取地址操作符 & 与 解引用操作符 *

0x05 操作数的类型长度 sizeof( )

0x06 按位取反 ~

0x07 前置、后置++

0x08 前置、后置 --

0x09 强制类型转换(type)

六、关系操作符

七、逻辑操作符

0x00 逻辑与 &&

0x01 逻辑或  ||

0x02 练习

八、条件操作符

九、逗号表达式

十、下标引用、函数调用和结构成员

0x00 下标引用操作符 [ ]

0x01 函数调用操作符 ( )

0x02 结构成员访问操作符 - 点操作符 .

0x03 结构成员访问操作符 - 箭头操作符 ->

十一章、表达式求值

0x00 隐式类型转换

0x02 算术转换

0x03 操作符的属性

作业

0x00 选择题

0x01 分析代码

0x02 交换两个变量(不创建临时变量)

0x03 统计二进制中1的个数

0x04 求两个数二进制中不同位的个数

0x05 打印整数二进制的奇数位和偶数位

答案

0x00 第一题:选择题

0x01 第二题:下列代码运行结果

0x02 第三题:不创建临时变量交换两个整数内容

0x03 第四题:统计二进制中1的个数

0x04 第五题:求两个数二进制中不同位的个数

0x05 第六题:打印整数二进制的奇数位和偶数位

一、算术操作符 0x00 概览

📌 注意事项:

      ① 除了 % 操作符之外,其他的几个操作符都可以作用于整数和浮点数;

      ② 对于 / 操作符,如果两个操作数 都为整数 ,执行整数除法;

      ③ 对于 / 操作符,只要有浮点数出现 ,执行的就是浮点数除法;

      ④ 对于 % 操作符的两个数 必须为整数;

0x01 整数除法

📚  定义:对于 / 操作数,如果两个操作数都为整数,执行整数除法;

❓   整数除法:即一个整数除以另一个整数结果为只保留整数;

💬 代码演示:

int main() {     int a = 5 / 2; // 5÷2 = 商2余1     printf("a = %d\n", a); // 👈 输出的结果是什么?       return 0; }

🚩 运行结果: a = 2

0x02 浮点数除法

📚  定义:只要有浮点数出现,执行的就是浮点数除法;

❓   浮点数除法:结果会保留小数部分( 给定对应的%前提下 );

💬 代码演示:

int main() {     double a = 5 / 2.0; // 5÷2 = 2.5,有1个浮点数,条件就成立,执行浮点数除法     printf("a = %lf\n", a); // 👈 输出的结果是什么?       return 0; } 

🚩 运行结果: a  = 2.500000

0x03 取模操作符

📚  定义:取模运算即 求两个数相除的余数 ,两个操作数必须为非0整数;

📌  注意事项:

      ① 两个操作数必须为整数;

      ② 两个操作数均不能为0(没有意义);

💬 代码演示:

int main() {     int a = 996 % 10; // 996 mod 10 = 6     int b = 996 % 100; // 996 mod 100 = 96     printf("%d\n", a);     printf("%d\n", b);       return 0; }

🚩  运行结果:6   96

❌  错误演示:

int main() {     double a = 5 % 2.0; // ❌ 操作数必须为整数     printf("a = %lf\n", a);       return 0; } 

🚩  运行结果:error: invalid operands to binary % (have 'int' and 'double')

int main() {     int a = 2 % 0; // ❌ 操作数不能为0     printf("%d\n", a);       return 0; } 

🚩  运行结果:warning: division by zero [-Wdiv-by-zero]

0x04 整除和浮点除的区分

💬 代码演示:我们想得到 1.2

int main() {     int a = 6 / 5;     printf("%d\n", a);          return 0; }

  🚩 运行结果:  1 ( 但是运行结果为1 )

❓  难道是因为我们用的是 %d 打印的原因吗?

int main() {     float a = 6 / 5;     printf("%f\n", a);          return 0; }

🚩 运行结果:  1.000000  ( 仍然不是想要的1.2,运行结果为1.000000 )

💡   解析:其实问题不在于存到a里能不能放的下小数的问题,而是 6 / 5 得到的结果已经是为1了(执行的是整除);

🔑  解决方案:把6改成6.0,或把5改成5.0,也可以都改,让它执行浮点数除法;

int main() {     float a = 6 / 5.0;     printf("%f\n", a);          return 0; }

🚩  运行结果:  1.200000

❓ 虽然代码可以运行,但是编译器报了一个 warning,让我们来瞅瞅是咋回事:

🔑  解析:直接写出的这个数字(6.0或5.0),编译器会默认认为它是 double 类型

                 那么计算后a的结果也会是 double 类型(双精度浮点数);

                 如果双精度浮点数的值放到一个单精度浮点数里的话,可能会丢失精度,

                 好心的编译器就发出了这样的一个警告,这个是正常的;

💡  如果你不想看到这样的警告,你可以这么做:

int main() {     float a = 6.0f / 5.0f; // 👈 “钦定” 为float单精度浮点数     printf("%f\n", a);          return 0; } int main() {     double a = 6.0 / 5.0;  // 👈 改成double     printf("%lf\n", a);          return 0; }

📚  关于精度丢失的现象:

      ① 有效数字位数超过7位的时候,将会四舍五入,会丢失较多精度;

      ② 在运行较大数值运算的时候,将有可能产生溢出,得到错误的结果;

二、移位操作符 0x00 概览

📚  概念: 移位操作符分为 "左移操作符" 和 "右移操作符" ;

📌  注意事项:

      ① 移位操作符的 操作数必须为整数;

      ② 对于运算符,切勿移动负数位(这是标准为定义的行为);

      ③ 左移操作符有乘2的效果,右移操作符有除2的效果(左乘2,右除2);

0x01 左移操作符

📚  移位规则:左边丢弃,右边补0 ;(左边的数给👴爬,至于爬多远,还要看操作数是多少)

💬  代码演示:

int main() {     int a = 2;     int b = a > 1; // 把a的二进制位向右移动一位     printf("b = %d\n", b); // 5 (右移操作符有除2的效果)       /*            00000000000000000000000000001010           0+0000000000000000000000000000101|0     */       return 0; }

🚩  运行结果:  b = 5

🔑  解析: 为了搞懂什么是算术右移,什么是逻辑右移,我们不得不了解整数的二进制表示方式:

0x03 整数的二进制表示方式(初步了解)

📚  负数-1要存放在内存中,内存中存放的是二进制的补码;

📌  整数的二进制表示形式(原反补):

      ① 原码:直接根据数值写出的二进制序列,即为原码;

      ② 反码:原码的符号位不变,其他位置按位取反,即为反码(如果不知道什么是按位取反,后面会讲);

      ③ 补码:反码 + 1,即为补码; (内存中存放的是补码)

📜  -1 的原码、反码、补码:

💬 此时回到上述问题,如果右移时采用逻辑右移:

int main() {     int a = -1;     int b = a >> 1;     printf("b = %d\n", b);       return 0; }

🚩  运行结果:  b = -1

🔑 图解逻辑右移与算数右移:

❌ 错误演示:操作数不能是负数!

int main() {     int num = 10;     num >> -1; // ❌  a hehe         printf("hehe\n");  // flag为真,打印hehe              if ( !flag ) // flag == 0 -> haha         printf("haha\n"); // flag为假,打印haha       return 0; }

🚩  运行结果:  hehe

0x02 负值 -

📚  作用:把一个数置为负数;

💬 负值的用法:

int main() {     int a = 10;     a = -a; // 在a前面放一个负号     printf("%d", a);          return 0; }

🚩  运行结果:  -10

0x03 正值 +

📚  作用:一般都省略掉了,和数学里面一样;

💬 加号一般都不写的:

int main() {     int a = +5; // 一般都省略掉了,和数学里一样     printf("%d", a);       return 0; }

🚩  运行结果: 5

0x04 取地址操作符 & 与 解引用操作符 *

📚  理解:

      ① 取地址操作符可以理解为取快递;

      ② 解引用操作符可以理解为拆快递;

      (指针章节会详解)

💬 用法演示:

int main() {     int a = 10;     int* pa = &a; // 取地址操作符  ( 随后将地址存放在int* pa里 )     *pa = 20; // 解引用操作符  通过p里存的值找到它所指向的对象;     // *p就是a, 将*p赋值为20,a就会变为20;          return 0; }

🔑  解析:

      ① 首先 int* pa 是一个指针变量(如果不知道什么是指针,可以暂且理解为是一个快递包裹);

      ② 快递包裹里装的是内存地址,我们使用 取地址操作符& 取出 a 的地址,存放到这个包裹里(int* pa = &a);

      ③ 这时,我们想修改 a 的值,我们要打开包裹进行修改,可以通过 解引用操作符* 将 a 修改为新的值(*pa = 20);

0x05 操作数的类型长度 sizeof( )

📚 作用:计算变量所占内存空间的大小,单位是字节;

📌 注意事项:

      ① sizeof 括号中的表达式不参与运算;

      ② sizeof 本质上不是函数,所以可以省略括号,但是 sizeof 后面是类型时不可以省略括号;

💬 sizeof 的用法:

int main() {     int a = 10;     char c = 'a';     char* pc = &c;     int arr[10] = {0};       /* sizeof 计算的变量所占内存空间的大小,单位是字节 */     printf("%d\n", sizeof(a)); //4;     printf("%d\n", sizeof(int)); //4;       printf("%d\n", sizeof(c)); //1;     printf("%d\n", sizeof(char)); //1;       printf("%d\n", sizeof(pc)); //4;   32位系统中     printf("%d\n", sizeof(char*)); //4;       printf("%d\n", sizeof(arr)); //40; 4x10=40     printf("%d\n", sizeof( int [10] )); //40;       return 0; }   

💬 下列代码的运行结果为什么?

int main() {     short s = 0;     int a = 10;       printf("%d\n", sizeof(s = a + 5));     printf("%d\n", s); }

🚩  运行结果: 2   0

❓ 为什么是 s 还是 0 呢? s = a + 5,s 不应该是 15吗……

🔑  解析:15个🔨15,sizeof 括号中的表达式不参与运算!

💬 下列代码输出后 (1) (2) (3) (4) 分别是多少(32位)?

void test1(int arr[]) //传参传过来的是首元素 {     printf("%d\n", sizeof(arr)); // (3) } void test2(char ch[]) {     printf("%d\n", sizeof(ch));  // (4) } int main() {     int arr[10] = {0};     char ch[10] = {0};     printf("%d\n", sizeof(arr)); // (1)     printf("%d\n", sizeof(ch));  // (2)     test1(arr);     test2(ch);       return 0; }

💡  答案:(1)40    (2)10   (3)4   (4)4

🔑  解析:

      ①  (1) 一个int型大小为4,数组大小为10,4x10 = 40,所以答案为40;

      ②  (3) 一个char型大小为1,数组大小为10,1x10 = 10,所以答案为10;

      ③  (3) (4) 数组名传参,传过去的虽然是是首元素地址,因为首元素的地址也是地址

           所以要拿一个指针来接收它。本质上,arr 和 ch 为指针,而指针的大小,

           是4个字节或者8个字节(具体是几个字节看操作系统),题目中为32位,所以答案为4;

❌ 错误示范:

int main() {     /* sizeof 后面是类型时不可以省略括号 */     int a = 10;     printf("%d\n", sizeof a );     // 可以省略 ✅     printf("%d\n", sizeof int);    // error! 不可以省略 ❌       return 0; }

🚩  运行结果:  error: expected expression before 'int'    printf("%d\n", sizeof int);

0x06 按位取反 ~

📚  作用:对一个数按位取反,0 变 1, 1 变 0;

📌  注意事项:

      ① 按位取反,1~0互换,包括符号位;

      ② 按位取反后,是补码;

💬 巧用按位取反:将某一个数的二进制位从右到左数的第三个数改为1;

int main() {     int a = 11;     a = a | (1访问结构指针成员rexp->member_namelexpL-R

++后缀自增lexp++rexpL-R

--后缀自减lexp--rexpL-R否!逻辑反!rexprexpR-L否~按位取反~rexprexpR-L否+单目,表示正值+rexprexpR-L否-单目,表示负值-rexprexpR-L否++前缀自增++lexprexpR-L否--前缀自减--lexprexpR-L否*间接访问*rexplexpR-L否&取地址&lexprexpR-L否sizeof取其长度,以字节表示sizeof rexp szieof(类型)

rexp

R-L否(类型)类型转换(类型)rexprexpR-L否*乘法rexp*rexprexpL-R否/除法rexp/rexp

rexp

L-R否%整数取余rexp%rexprexpL-R否+加法rexp+rexprexpL-R否-减法rexp-rexprexpL-R否rexprexpL-R否>大于rexp>rexprexpL-R否>=大于等于rexp>=rexprexpL-R否 i) & 1) != ((n >> i) & 1) ) {             count++;         }      }     printf("%d\n", count);       return 0; }

2. 异或法,然后统计二进制中有几个1

int NumberOf1(int n)  {     int count = 0;     while(n) {         n = n & (n - 1);         count++;     }     return count; }   int main() {     int m = 0;     int n = 0;     scanf("%d%d", &m, &n);       int count = 0;     int ret = m ^ n; // 相同为0,相异为1     // 统计一下ret的二进制中有几个1,就说明m和n的二进制位中有几个位置不同     count = NumberOf1(ret);     printf("%d\n", count);       return 0; } 0x05 第六题:打印整数二进制的奇数位和偶数位

💬  说明:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列;

int main() {     int n = 0;     scanf("%d", &n);     // 获取n的2进制中的奇数位和偶数位     int i = 0;     // 打印偶数位     for(i=31; i>=1; i -= 2) {         printf("%d ", (n >> i) & 1);     }     printf("\n");     // 打印奇数位     for(i=30; i>=0; i-=2) {         printf("%d ", (n >> i) & 1);     }       return 0; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3