五、操作符复习 |
您所在的位置:网站首页 › 浮点数的用法 › 五、操作符复习 |
目录 一、算术操作符 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/rexprexp 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 |