int main(void)
{
int a = 3;
a += (a++); //执行后a=7。“=”右边a=4(此时没有将a=4放入a的地址中),“=”左边a=3,因此加完a=7,这句话执行完后,更新a的数据为7.
a += (++a); //执行后a=16。“=”右边a=8(此时将a=4放入a的地址中),“=”左边a=8,因此加完a=16,这句话执行完后,更新a的数据为7.
}
再比如:int main()
{
int a[] = {1,2,3,4,5,6};
int i=0;
printf("%d", a[i++]); //执行结果为1,此时相当于输出a[0]的数值,在该语句执行结束后遇到“;”后才更新i的数值为1.
printf("%d", a[++i]); //执行结果为3,此时相当于输出a[3]的数值,在i++时,将i的数值更新为1+1=2,之后再将a[2]输出。
}
int main(void)
{
int a = 3;
a += (a++); //执行后a=7。“=”右边a=4(此时没有将a=4放入a的地址中),“=”左边a=3,因此加完a=7,这句话执行完后,更新a的数据为7.
a += (++a); //执行后a=16。“=”右边a=8(此时将a=8放入a的地址中),“=”左边a=8,因此加完a=16,这句话执行完后,更新a的数据为16.
(++a) += (a++); //执行后a=35。“=”左边a=17(此时将a=17放入a的地址中),“=”左边a=18,因此加完a=35,这句话执行完后,更新a的数据为35.
(a++) += a; //此句错误,编译不通过,因为不能对a++右值操作.
两个相同的数异或后结果为0,否则为1,且满足交换律:
若A ^B ^C ^D ^E ^F ^D,则其等价于A ^B ^C ^E ^F。这一性质通常用于寻找数成对出现时缺失某一个数。
例1:假设有一个文件,文件中每行记录一个数,且每个数在文件中都出现两次,但某一个数不小心被删除了,问怎么快速找出这个数?
解析:由于两个数异或的结果为0,故可以依次读入文件中的每个数,并进行异或操作, 最后得到的数,就是不小心删除的数字。
例2:不适用第三方变量,如何交换两个变量的值。
解析:使用异或。
a = a^b;
b = a^b;
a = a^b;
例2:不用算术运算符实现两个数的加法。
解析:
1)先不考虑仅为,安慰计算各位累加(用抑或实现),得值a;
2)然后计算仅为,并将进位的数值左移,得值b。若b为0,则a就是加法运算的结果;若b不为0,则a+b即得结果。
int add_no_arithm(int a, int b)
{
if (b==0) return a; //当没有进位时
int sum = a^b;
int carry = (a&b) <<1;
return add_no_arithm(sum, carry);
}
例e:如何实现位操作求两个数的平均值?
解析:(x&y)+((x^y)>>1)
。如x:01010,y:0110。x&y为0100,即取x、y中对应位都为1的位,并将结果置位1,相当于取得了都为1的位相加的一半。
(x^y)结果为00110,即取x、y中对应为只有一个1的位,并将结果的对应为置1,由于最终结果是平均值,故除以2(用右移1位实现)。
int *ip;
ip=0;
上式中将int类型的0转换为int*类型的空指针。
char a=0xe0;
int b=a; //此时b为0xffffffe0,因为二进制a=11100000,转换成int会作符号位扩展,此时a符号位为1,故补1
当前大多数的系统都是讲int低字节赋值给short,而将高位舍去。
short a = 0x1111ffff; //此时a=0xff
unsigned short a = 0x1111ffff; //此时a=0xff
例1:下面两段代码中for分别执行了多少次?
unsigned short i,j;
for(i=0,j=2;i!=j;i+=5,j+=7){}
unsigned short i,j;
for(i=3,j=7;i!=j;i+=3,j+=7){}
解析:第一个执行了32767次,第二个执行了16383次。注意数据类型为unsigned short,题目中j比i大,而且增长快,实际中是不可能相等的。但是当j超出unsigned short(超过65536)时,会发生转换,转换规则为j%65536(即重新从0开始)。故i=j时,j已经超过65536后才可以满足,因此可以列出:(0+5x)+65536=2+7x,解得x=32767。第二段代码同理。
1)整型提升
在表达式计算中,C++将bool、char、unsigned char、signed char、short和signed short型值都会自动换成int型。
2)运算时的转换
当运算设计两种类型时,较小的类型将会被转换成较大的类型,由类型大小低到高依次是:
int->unsigned int->long->unsigned long->float->double->long double
例:下面程序的输出结果为()。
unsigned int a=1;
count<<a*-2<<endl;
负数在计算机中通常以补码的形式存储。
int a=5,; //对应二进制位00000000 00000000 00000000 00000101 。
那对于int a=-5;而言那,在存储时需要先求得其源码,再转换成反码,反码+1=补码,补码才是-5在内容中存储的实际二进制数据。
-5对应的源码 10000000 00000000 00000000 00000101
-5对应的反码 11111111 11111111 11111111 11111010 (对源码进行求反,1变0,0变1)
-5对应的补码 11111111 11111111 11111111 11111011 (反码+1)
切记:正数的反码和补码与原码相同,只有负数的不同。
例:小端机器下,下面程序的运行结果是什么?
unsigned int a=0x1ffffff7;
unsigned char b=a; /语句1/
char c=a; //语句2
char* p=(char*)&a; //语句3
printf("%x, %x, %x",b, c, *p);
解析:f7, fffffff7, fffffff7.
语句1是的b为f7,因为发生截断,将a低字节赋值给b,而将高位舍去。
同理,c也为f7。
但是b为无符号数,c为有符号数,当printf把b、c压入栈时,需要入栈4个字节,需要做符号扩展,b为无符号数,高位补0;c为有符号数,且符号位为1(最高位),因此高位补1。所以最终的输出b=0xf7,c=0xfffffff7。
而p是指向a的字地址(低地址)处,因为是小端机器,故字地址处存放的是f7,printf入栈时,需要入栈4个字节,同样需要对其做符号扩充,因为*p是char类型,且符号位位1,所以高位补1。
例。设intx=4,则执行以下语句:x+=x-=x-x–;后,x的值为()。
例:请写出如下代码的运行结果。
int main()
{
int a,b,c,d;
a=0;
b=1;
c=2;
d=3;
printf("%d", a+++b+c+++d++);
}
解析:该程序的运行结果为6。由于++都是后缀形式,故0+1+2+3=6。注意,这里a++、c++、d++均在本条语句执行结束后才更新。
例。下述程序的运行结果是()。
int main()
{
int a,b,c;
c=a=0x30, b=0x60;
a=c | b >> 4;
cout<<a<<'_'<<b<<'_'<<c<<endl;
}
解析:54_96_48。移位运算符的优先级较高,因此先执行移位操作,得a=0x36,即54。
例:int a1=x+y-z, int a2=x-z+y;
这样的语句是成立的,且a1=a2,,一开始也许会觉得这句话肯定不对,因为会溢出,单子VS2010下a1=a2,这是因为一处会有标识位,减的时候回考虑到这个标识位的作用,因此这句话正确。
例。字节为6的二进制有符号整数,其最小值是()。
解析:-32。此时该6位数为100000,因此对应的数应该是-(011111再取反)=-(100000)=-32。
例。若有以下声明和语句:
struct student{
int age;
}std, *p;
p = &std;
则以下对结构体变量std中成员age的引用方式正确的是()(多选)。
例。以下代码的输出结果为()。
int func(std::vector<int> vec)
{
static int k=2;
std::vector<int>::reverse_iterator it;
for(it=vec.rbegin(); it!=vec.rend(); ++it){
k += *it%2==0? ++*it: (*it)++; //语句1
}
return k;
}
int main(){
std::vector<int> vec;
for (int i=0;i<4;i++){
vec.push_back(i);
printf("%d\n", func(vec));
}
return 0;
}
解析:3 5 10 18。为了更直观的看出来效果,我在每次开始前后将数据输出,修改后代码如下:
#include
#include
#include
using namespace std;
int func(std::vector<int> vec)
{
cout<<"input:---- "<<endl;
static int k=2;
std::vector<int>::reverse_iterator it;
for(it=vec.rbegin(); it!=vec.rend(); ++it){
printf("Before: k = %d it=%d *it=%d\n", k, it, *it);
k += *it%2==0? ++*it: (*it)++; //语句1
printf("After: k = %d it=%d *it=%d\n", k, it, *it);
}
return k;
}
int main(){
std::vector<int> vec;
for (int i=0;i<4;i++){
vec.push_back(i);
printf("Output: k=%d\n", func(vec));
}
return 0;
}
输出结果如下:
input:----
Before: k = 2 it=6421920 *it=0
After: k = 3 it=6421928 *it=1
Output: k=3
input:----
Before: k = 3 it=6421920 *it=1
After: k = 4 it=6421928 *it=2
Before: k = 4 it=6421920 *it=0
After: k = 5 it=6421928 *it=1
Output: k=5
input:----
Before: k = 5 it=6421920 *it=2
After: k = 8 it=6421928 *it=3
Before: k = 8 it=6421920 *it=1
After: k = 9 it=6421928 *it=2
Before: k = 9 it=6421920 *it=0
After: k = 10 it=6421928 *it=1
Output: k=10
input:----
Before: k = 10 it=6421920 *it=3
After: k = 13 it=6421928 *it=4
Before: k = 13 it=6421920 *it=2
After: k = 16 it=6421928 *it=3
Before: k = 16 it=6421920 *it=1
After: k = 17 it=6421928 *it=2
Before: k = 17 it=6421920 *it=0
After: k = 18 it=6421928 *it=1
Output: k=18
例。写出float x与零值比较的if语句。
解析:float类型只能保证6位有效数字,double能保证10位有效数字。
if(x>-0.000001 && x<0.000001)
例。计算表达式 x 6 + 4 x 4 + 2 x 3 + x + 1 x^6+4x^4+2x^3+x+1 x6+4x4+2x3+x+1最少需要()次乘法。