1.变量的作用域:
下面这段代码中,i虽然在声明时已经可见,但是main里的i跟外面的i无关,这里虽然编译器不会报错,但是运行后会提示i是一个未定义的值,而不是1.
<pre>int i = 1;
void main(){
int i = i;
}</pre>
2.位运算和逻辑运算的区别
&是位运算,而&&为逻辑运算。||是只要有一个操作数是1结果就是1....
<pre>int y = 4, x = 3;
cout << y&x; //输出0
cout << y&&x; //输出1
cout << y|x; //输出7
cout << y||x; //输出1
</pre>
3.位运算的例子
- 求的结果是x的二进制数中有多少位是1:
<pre>int func(int x){
int count = 0;
while(x) {
count++;
x = x&(x-1);
}
return count;
}
</pre>
- 判断一个数是不是2的N次方:因为所有2的次方都可以写成10,100,...所以只要用位与运算看看第一位是不是1就好了。
<pre>!(x&(x-1))</pre> - 求两个数的平均值:与运算得到的是相同位的一半,异或除以二得到了不同位的一半
<pre>int f(int x,int y){
return (x&y)+((x^y)>>1);
}</pre>
4.i++的问题
这里ptr最初指向arr[0]=129,然后ptr自增指向了arr[1],注意在输出时,先计算的是逗号表达式右边的表达式,即ptr自增到arr[2],输出8,然后*ptr也输出8.
<pre>main(){
int arr[] = {6,7,8,9,10};
int ptr = arr;
(ptr++) +=123;
printf("%d,%d\n",ptr,(++ptr));
}</pre>
5.float内存方式
浮点数据就是按下表的格式存储在4个字节中:
Address+0 Address+1 Address+2 Address+3
Contents SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
S: 表示浮点数正负,1为负数,0为正数
E: 指数加上127后的值的二进制数
M: 24-bit的底数(只存储23-bit)
主意:这里有个特例,浮点数 为0时,指数和底数都为0,但此前的公式不成立。因为2的0次方为1,所以,0是个特例。当然,这个特例也不用认为去干扰,编译器会自动去识别。
<pre>通过上面的格式,我们下面举例看下-12.5在计算机中存储的具体数据:
格式 SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
二进制 11000001 01001000 00000000 00000000
16进制 C1 48 00 00
可见:
S: 为1,是个负数。
E:为 10000010 转为10进制为130,130-127=3,即实际指数部分为3.
M:为 10010000000000000000000。 这里,在底数左边省略存储了一个1,使用 实际底数表示为 1.10010000000000000000000
到此,我们吧三个部分的值都拎出来了,现在,我们通过指数部分E的值来调整底数部分M的值。调整方法为:如果指数E为负数,底数的小数点向左移,如果指数E为正数,底数的小数点向右移。小数点移动的位数由指数E的绝对值决定。
这里,E为正3,使用向右移3为即得:
1100.10000000000000000000
至次,这个结果就是12.5的二进制浮点数,将他换算成10进制数就看到12.5了,如何转换,看下面:
小数点左边的1100 表示为 (1 × 23) + (1 × 22) + (0 × 21) + (0 × 20), 其结果为 12 。
小数点右边的 .100… 表示为 (1 × 2-1) + (0 × 2-2) + (0 × 2-3) + ... ,其结果为.5 。
以上二值的和为12.5, 由于S 为1,使用为负数,即-12.5 。
所以,16进制 0XC1480000 是浮点数 -12.5 。</pre>
<pre>上面是如何将计算机存储中的二进制数如何转换成实际浮点数,下面看下如何将一浮点数装换成计算机存储格式中的二进制数。
举例将17.625换算成 float型。
首先,将17.625换算成二进制位:10001.101 ( 0.625 = 0.5+0.125, 0.5即 1/2, 0.125即 1/8 如果不会将小数部分转换成二进制,请参考其他书籍。) 再将 10001.101 向右移,直到小数点前只剩一位 成了 1.0001101 x 2的4次方(因为右移了4位)。此时 我们的底数M和指数E就出来了:
底数部分M,因为小数点前必为1,所以IEEE规定只记录小数点后的就好,所以此处底数为 0001101 。
指数部分E,实际为4,但须加上127,固为131,即二进制数 10000011
符号部分S,由于是正数,所以S为0.
综上所述,17.625的 float 存储格式就是:
0 10000011 00011010000000000000000
转换成16进制:0x41 8D 00 00
所以,一看,还是占用了4个字节。</pre>
6.类型转换
如果定义了float a = 1.0f,可以算出他的存储为 3f800000h,其中
M=0,E=0+127=01111111,S=0。因此下面&a将取值到3f800000h,而再对其强制转换成int会得到这个地址的十进制int值。
<pre>(int&)a;</pre>
下面这段代码中,第一个转换是把int转换成char,这时4字节截断为1字节,因此i变为000000f7。而后一个是地址的变化,即一个指向int 的指针强制转换成一个指向char的指针,地址并没有变化,只是在指针+1时移动的步长变为了sizeof(unsigned char),即移动1而不是4.
<pre> unsigned int a = 0xfffffff7;
unsigned char i = (unsigned char)a;
char *b = (char*)&a;
printf("%08x,%08x",i,*b);</pre>
7. ab交换
- 返回两个数中较大的那一个
<pre>return (a+b+abs(a-b))/2;</pre>
- 交换两个数的值:通常想到 a = a+b; b = a-b; a = a-b;但是这时如果两个数都很大有可能溢出。所以用位运算来做。
<pre>a = a^b;
b = a^b;
a = a^b;
</pre>