- 整型:1/2–> 0
- 浮点数除法: 必须左右有1带小数点
- 移位操作符:
整数二进制表示:原码、反码、补码;
正整数三个码相同
负的整数原码、反码、补码需要计算
整型4字节:32位
7表示为:
0*(29)+111
-7表示为:
1+0*(28)+111 原码
1 11…1111 + 0000反码 (原码符号位不变,其他位取反)
1 11…1111+ 0001 补码(反码+1)
整数在内存中存的是补码
移位:
左移:比如a=7: 末尾补0
0…000000111 左移补0 变为: 0…001110 变大了加了2的多少次
但是a不会变
如果 a = -7
补码:(左移后) 1111111111…110010
直接减1取反 11111…110001 ->(取反)
符号位不变1 000… 001110 -> 2+4+8=14
最终结果 - 14
右移:特别,分为两种, 取决于编译器:
算术右移:右边丢弃,左边补原符号
逻辑移位:右边丢弃,左边补0
vs采用算术移位
移位不能用负数
最终结果:正数两种都不变,负数逻辑
总结:
左移:不论正数负数,结果都是乘2
右移:
- 位操作符
& 按二进制位与:
| 按二进制位或:
^ 按位异或: 异为1,同为0
程序里面做这些,都是以补码来做的
一道面试题:
- 不创建临时变量,交换两个整数值:
思路:1. 简单:
int a = 3; int b =5;
a = a+b; // (需要a+b不溢出)
b = a- b;
2. 正规: 以a = 3、b = 5举例:
a = a ^ b; 3 ^5
b = a ^ b; 3 ^ 5 ^5 = 3
a = a ^ b; 3 ^ 5 ^ 3 = 5
如上,三次异或实现了交换 - 操作符
单目:只操作一个操作数
sizeof()其实是个单目运算符
++、–都是单目运算符
强制类型转型也是单目运算符
两个数字比较的时候: 123 == 5: 是在比较值,而
string “abc” == “abcdef” 是在比地址
4. int a[10] = {0} 这样只是初始化了第一个
5. 弄懂stringcpy?,它为什么不直接赋值字符串呢??
*ps 是因为ps是指针,指向结构体,所以需要
练习:
- 求整数在内存中的二进制存储值:
get_bit中1个数思路:
让数字和1做&运算,如果为1则这个位为1,
然后1再一次左移一次<<, 总共左移多次,
这样让这个数字不断与自己不同位上的1做与,然而得到的结果除了第1位是1,但其它不是1,但是是2的某个次,因为它不在第一位做与。
int get_bit(int a)
{
int b = 1;
int count = 0;
int f = a;
while (f)
{
int t = 0;
t = a & b;
if (t != 0)
{
count++;
}
f /= 2;
if (!f) { break; }
b = b << 1;
}
return count;
}
int main()
{
int a;
int b;
scanf("%d", &a);
scanf("%d", &b);
int res = a^b;
// 看多少个位是1
res = get_bit(res);
printf("%d", res);
return 0;
}
- 打印整数二进制的奇数位和偶数位
思路:
放入数组存与结果,不是0就存入当前位置,
注意:256是2的8次,但它是1+(0)*8
因为二进制第一个位是2的0次
int convert_bit(int a, int res[33])
{
int f = a;
int b = 1;
int i=1;
while (f)
{
int t = a & b;
if(t!=0)
{
res[i] = i;
}
b = b << 1;
f /= 2;
if (!f) { break; }
i++;
}
return i;
}
// 打印整数二进制全部
int main()
{
int a;
scanf("%d", &a);
int first;
int res[33] = { 0 };
first = convert_bit(a, res);
printf("数字的二进制最高位为%d\n", first);
// 因为二进制最后是2的0次,所以最高位是2的first-1次
for (int i = first; i>=1;i--)
{
if (res[i] != 0)
{
printf("%d", 1);
}
else
{
printf("%d", 0);
}
}
return 0;
}
更牛的写法
统计二进制中1
以往思路:求10进制每一位,不断模10除10,求2进制每一位,不断模2除2得每一位。(负数不合适)
新思路:上面写法的改进
scanf(n);
int count = 0;
// 要求数向右移动32位,每次挪动都与1做&,统计1数量
for(int i=0;i<32;i++)
{
if(((n>>i)&1)==1) {count++;}
}
return count;
n = n&(n-1); 每次让一个位归0,看需要几次变为0
1111 ->15
1110 ->14
1110 -> 14 做& n = 14
1101 -> 13
1100 -> 12 做& n = 12
1011 -> 11
1000 -> 8 做& n = 8
0111 -> 7 做& n = 7
0000 ->0 0
做了4次,所以有4个1 负数也适用
int count = 0;
while(n)
{
n = n&(n-1);
count++;
}
全局变量、静态变量在静态区,且静态变量不初始化会被初始化为0
int i;
int main()
{
i--; // 全局变量不初始化默认为0 这里自减结果为-1
if(i>sizeof(i)) // sizeof返回 unsigned int 无符号整型
// 不同类型的数比较会转为较大的类型,即左边负数-1:1000转为理解成1000。。。会认为非常大,所以这个if成立
return 0;
}
问答:
- 为什么int类型的范围是:-2147483648~2147483647 【-2^31, 2^32-1】?
答:int有32位,第1位是符号位,正数部分可以表示2^31中情况,然而其中有全0的情况,最大是2^32 -1。而负数有2^31次中情况,但是+0和-0原码不一样,补码也不一样,规定0作为0的原码、补码和反码,而-0的补码作为-(2^31)-1 = 2147483648,这个数字是规定,它没有原码,因为会溢出。所以-1的补码是边界值的形式补码。