做网站设计答辩问题/百度号码认证平台官网首页
整型提升和截断
操作符详解 (只讲易错点)
文章目录
- 操作符详解 (只讲易错点)
- 算术操作符
- 移位操作符
- 总结:右移一位 具有 /2效果 右移2位 具有 /4 效果 右移三位 具有 /8 效果(右移效果只针对正数).......
- 左移一位 具有x2效果 左移两位 具有x4效果 左移三位 具有x8效果 (左移效果针对所有数)........
- 位操作符
- 这里我出两道关于位操作符的习题
- 数字交换
- 数字的二进制(补码)有多少个1 ???
- 复合运算符
- 单目运算符
- **再问,那如果我想把1111改回去呢????**
- 条件操作符
- 逗号操作符
- 下标引用,函数调用,以及结构成员
算术操作符
分为 + - * / %
注意点:
- "/" 如果是整型除法,其结果是商,注意,我说的是商,如 a ÷ b = c …d,c叫做商,d叫做余数. 例子: 9 / 4 = 2
- 如果两边有一个小数,则进行的就是小数除法. 例子: 9 / 4.0 = 2.250000
- "%" 代表求模运算,即余数, a % b = c; 其中c的范围在 [0,b)
移位操作符
分为左移操作符 << 和 右移操作符 >>
在讲解移位操作符以前,我要强调一个概念 原码反码补码 (如果没有基础的,建议百度下)
并且一个整数4个字节,由32位组成
其中正数的 原码反码补码 相同
负数的 反码等于原来相对应的正整数的原码所有位按位取反.
负数的 补码等于其反码最低位 加 1
而在计算机内存中,所操作的一切都是操作的 补码,补码,补码,补码!!! 重要的事情多说几遍,只是显示的时候才把补码还原回原码,然后转换成十进制.
">>": 右移操作符,右移的是二进制.并且左右移操作符都不能移动负数个位,比如 a>>-2 这种写法就是错的
- 右移操作却又分为两种: 1.算术右移 2.逻辑右移 一般的编译器都是采取的算术右移
* 算术右移: 右边丢弃,左边补 **符号位**.* 逻辑右移:只管右移就行,左边补0;
语法: a >> b; 意思是a的二进制 向右移动b位
例如 16 >> 1;
00000000 00000000 00000000 00100000 (16的二进制,正数,所以原反补相同)0000000 00000000 00000000 00010000 (右边移动一位)000000000 00000000 00000000 0010000 (左边补符号位 因为是正数,所以补符号位0)
所以 16 >> 1 的结果是 8,同样的操作, 8 >> 1的结果是4 ,即 >> 具有 /2 的效果,注意 / 的效果,上面已经讲到.
其次我们看 -1 >> 1
00000000 00000000 00000000 00000001(正1的原码)
-1的反码:
11111111 11111111 11111111 11111110 (对应正数所有位按位取反,最高位是符号位,代表负数)
补码:
11111111 11111111 11111111 1111111 (反码加一)
再次强调,计算机操作的是补码
所以 -1 往右边移动一位,再在左边补符号位1,发现补码值不变,但是计算机想要显示该数字,又需要将
32个1 补码还原回去,还原回去发现为
10000000 00000000 00000000 00000001 (-1原码,最高位是符号位)
还是数字-1,所以 -1 >> 1的值还是-1
“<<” 左移操作符的运算与上面一模一样,只是 成为 左边移动,右边补0;
例如 -1 << 1;
-1的补码是
11111111 11111111 11111111 11111111
左移一位,右边补0;
11111111 11111111 11111111 11111110
补码还原表示为
10000000 0000000 00000000 00000010 (值为-2)
总结:右移一位 具有 /2效果 右移2位 具有 /4 效果 右移三位 具有 /8 效果(右移效果只针对正数)…
左移一位 具有x2效果 左移两位 具有x4效果 左移三位 具有x8效果 (左移效果针对所有数)…
位操作符
- & 按位与 (两个都是1才是1,否则0)
- 110101
- 101110
上面两个结果为 : 100100
- | 按位或 (只要有1就是1)
- 1011011
- 0101100
上面两个结果为: 1111111
- ^ 按位异或 (相同为0,相异为1)
- 1010001
- 1010101
上面两个结果为:0000100
这里我出两道关于位操作符的习题
数字交换
给出两个数字 a和b ,要求除了这两个变量以外,不准创建任何变量,达到ab交换
代码如下:
#include <stdio.h>
int main()
{int a,b;scanf("%d%d",&a,&b);a = a^b;b = a^b;a = a^b;printf("%d %d", a, b);return 0;
}
what???这是什么鬼???请听我一一道来
我们以 a = 3,b = 5为例
a ^ b = m; 那么我们反过来推导,m ^ a = b? 对吧!? m^b = a? 对吧!?
所以这段代码
a = a^b;
b = a^b;
a = a^b;
为了更好理解我暂时用**am**代替a^b出来的值a(图中m),
am = a^b;
b = am ^b; (新得到的值其实是a,只是把值赋给了b)
a = am ^ b;(am异或b,其实是异或的a,能理解吧?那么异或a得到的值就是b,所以赋值给a,)
所以这样就是不要变量达到了完美的交换 妙吗?妙就点个赞嘛…
数字的二进制(补码)有多少个1 ???
我们先不管二进制,假设给你一个数字a = 12334565,喊你求这个数字有几个3?
正常思路是不是 a%10 == 3 a = a/10 --> a%10 == 3 a = a/10 --> a%10 == 3 a = a/10这样循环下去计算?
那么我们二进制也是一样 a%2 == 1 a = a/2 这样循环下去数,\
代码方法一:
#include <stdio.h>
int main()
{int n = 15;int count = 0;while (n){if (n % 2 == 1)count++;n /= 2;}printf("%d", count);return 0;
}
但是这样写只能算正数,所以有缺陷
下面我就介绍 位操作
我们知道只有数字1 & 1 结果才是1
步骤一 所以我们可以通过把一个数字的二进制与00000000000000000000000000000001 相&
步骤二 如果结果为1,代表末尾为1
步骤三 然后把该数字右移一位,再 与 000000000000000000000000000000001相&
以此循环…
代码二
#include <stdio.h>
int main()
{int n = -1;int count = 0;for(int i = 0;i<32;i++){if (n & 1 == 1)count++;n = n >> 1;}printf("%d", count);return 0;
}
复合运算符
这个没什么讲的 ,就是组合起来操作
例子:
a = a + 3 <==> a += 3
a = a & 2 <==> a &= 2
a = a >> 1 <==> a >>= 1
单目运算符
目,眼睛. 即这个操作符只需要一个操作数
例如 !3 -4 &a a++
这里主要讲解一下 ++ – ~ sizeof
其中sizeof()和strlen()的区别请看这里 >>>>>>>>>>
这里有个小题:
#include <stdio.h>
int main()
{short s = 0;int a = 10;printf("%d\n", sizeof(s = a+5));printf("%d\n", s);return 0;
}
结果是多少???
2 0
因为sizeof里面的表达式中s不参与运算
++ :
-
前置++ 即先++,再使用
-
后置++ 即先使用,再++
-
#include <stdio.h> int main() {int a = 5;printf("%d ", a++);printf("%d", a);return 0; }/*结果*/ 5 6/*因为它先使用了a的值,然后再++*/
-
#include <stdio.h> int main() {int a = 5;printf("%d ", ++a);printf("%d", a);return 0; }/*结果*/ 6 6
--
的使用和++
一样
-
~ 按位取反
-
问: 假设我想把 00001011 的倒数第三个0改为1 怎么用代码弄?
-
很简单,我们只有把它和00000100 **相 |**一下就行,那么00000100怎么来的?? 数字1左移两位 1<<2
-
代码:
-
#include <stdio.h> int main() {/*1011代表的是 11*/int a = 11;int ret;ret = a | (1<<2);printf("%d", ret);return 0; }/*结果是 15*/ 1111刚好就是15
-
-
再问,那如果我想把1111改回去呢???
- 00000000 00000000 0000000 00001111
- 我们需要把它和11111111 11111111 11111111 111110111 相&
- 那11111111 11111111 11111111 111110111怎么得来的呢???
- 00000000 00000000 00000000 00000100取反得来
- 00000000 00000000 00000000 00000100而这个又是1左移两位
- 00000000 00000000 00000000 00000001(数字1)
所以逻辑是 首先 1<<2 然后取反 最后相与
代码:
#include <stdio.h>
int main()
{int a = 15;int ret;ret = a & (~(1<<2));printf("%d", ret);return 0;
}/*结果是11*/
条件操作符
exp1?exp2:exp3
表达式exp1如果成立,则返回表达式2的值,否则返回表达式3的值
例如我们需要把 a,b中的大值给max,小值给min
#include <stdio.h>
int main()
{int a = 15,b = 24;int max,min;max = a>b?a:b;min = a>b?b:a;printf("max = %d min = %d", max,min);return 0;
}
逗号操作符
从左向右依次执行,但是只返回最后一个表达式的值
例如:
int a = 3,b = 4;
c = (a>b,a = b*4,b = a+2)
c等于多少呢??? 答案: 18
运用:
#include <stdio.h>
int main()
{a = get_val();count(a);while(a>0){a = get_val();count(a); //语句}return 0;
}/*是不是重复了????????写成这样*/#include <stdio.h>
int main()
{ while(a = get_val(),a>0,count(a)){//语句}return 0;
}
下标引用,函数调用,以及结构成员
[] 下标调用
() 函数调用操作符
. 访问结构体成员
-> 结构体指针访问
- num[10] = {2,4,5,8,4,21,4,57,5,1}
- 那么 num[2] = 5
fun(a,b);
.
struct student {char name[10];int age;char sex[10]; };#include <stdio.h> int main() {struct student xiaoming = { "小明",100,"人妖" };/*访问结构成员*/printf("姓名:%s\n", xiaoming.name);printf("年龄:%d\n", xiaoming.age);printf("性别:%s\n", xiaoming.sex);return 0; }
->
struct student { char name[10]; int age; char sex[10]; };#include <stdio.h> int main() { struct student xiaoming = { "小明",100,"人妖" }; struct student* people = &xiaoming; /*访问结构成员*/printf("姓名:%s\n", people->name); printf("年龄:%d\n", people->age); printf("性别:%s\n", people->sex); return 0; }