【程序员面试宝典】错题好题汇总ch5

错题,知识盲点、查漏补缺
好题,开阔思路、锻炼思维

ch5

1.
#include<iostream>
using namespace std;
int i = 1;
int main(){
 
 int i = i;
 cout<<i<<endl;
 return 0;
}
结果与分析:
main中的i从声明起就已经覆盖了全局变量i,所以直接用未定义的i进行赋值结果是未定的。
 
2.
#include<iostream>
using namespace std;
int func(int x){
 
 int count = 0;
 while(x){
 
  count++;
  x = x&(x - 1);
 }
 return count;
}
int main(){
 
 cout<<func(9999)<<endl;
 return 0;
}

 

结果与分析:
一开始看到这个题,我第一反应是按照x&(x-1)这条语句去执行一下,然后我笔算了一下9999 = 2^13 + 2^10 + 2^9 + 2^8 + 2^3 + 2^2 + 2 + 1,二进制表示就是10011100001111。这时候发现如果x位与x-1的话,会消耗掉最低位的1,连续执行下去的话就会把所有的1全部消耗掉。所以最后得出count是8。
思路开拓:
1.计算一个十进制数的二进制表示中1的个数呢?
很明显上面的程序就是答案。
2.计算一个十进制数的二进制表示中0的个数呢?
可以仿照求十进制数的个数,通过除2进行计算。
另外,向右位移的效果和除法类似:
int count_zero(int x){
 
 int count = 0;
 int count_one = 0;
 while(x){
 
  count_one += x&1;
  count++;
  x = x>>1;
 }
 return count - count_one;
}

 

 
3.
#include<stdio.h>
int main(){
 
 int  b = 3;
 int arr[] = {6,7,8,9,10};
 int * ptr = arr;
 *(ptr++) += 123;
 printf("%d,%d\n",*ptr,*(++ptr));
 return 0;
}

 

结果与分析:
主要考察,1、函数参数入栈的顺序
              2、*(ptr++)+=123;分解为:*ptr = *ptr + 123;ptr++;

衡量参数在栈上的位置,就是离开确切的 函数调用点(call f)有多远。已经确定的参数,它在栈上的位置,

不应该依 赖参数的具体数量,因为参数的数量是未知的!

所以,选择只能是,已经确定的参 数,离开函数调用点有确定的距离(较近)。满足这
个条件,只有参数入栈遵从自右向左规则。 也就是说,左边确定的参数后入栈,离函数
调用点有确定的距离(最左边的参数最后入栈,离函 数调用点最近)。

这样,当函数开始执行后,它能找到 所有已经确定的参数。根据函数自己的逻辑,它负
责寻找和解释后面可变的参数(在离开调用点 较远的地方),通常这依赖于已经确定的
参数的值(典型的如prinf()函 数的格式解释,遗憾的是这样的方式具有脆弱性)。

详情请看:http://www.cnblogs.com/forlina/archive/2011/09/12/2174164.html
 
4.
#include<iostream>
using namespace std;
int main(){
 
 float a = 1.0f;
 cout << (int)a << endl;
 cout << (int&)a << endl;
 cout << boolalpha << ( (int)a == (int&)a ) << endl; // 输出什么?
 float b = 0.0f;
 cout << (int)b << endl;
 cout << (int&)b << endl;
 cout << boolalpha << ( (int)b == (int&)b ) << endl; // 输出什么?
 return 0;
}

 

结果与分析:
考察点一:

(int &)a 就表示 不管 a 是什么,我都当他是一个int变量。

从机器码的角度来说,变量a会被翻译成一个内存地址,(int &)a 就是说,这个内存地址里的内容它是一个整数。

(int)a 呢不同:如果 a 不是整数,就会按规则转换成整数,存入另一个地址(或临时变量)中去。

浮点数的 1.0f 在内存里是这样表示的:

0011 1111 1000 0000 00000000 00000000

这个32位二进制数被当作整数输出就是:

2^29+2^28+2^27+2^26+2^25+2^24+2^23=1065353216

而整数的 1 在内存里是这样表示的:

0000 0000 0000 0000 00000000 00000001

(int&)a 相当于*(int*)&a ; *(int*)(&a) ; *((int*)&a)

所以 (int)a != (int&)a

浮点的0和整数的0 在内存里都是:

0000 0000 0000 0000 00000000 00000000

所以 (int)b == (int&)b

参考:http://blog.csdn.net/cszdhhz/article/details/6877333#

考察点二:

另外,boolalpha的作用是使bool型变量按照false、true的格式输出。如不使用该标识符,那么结果会按照1、0的格式输出。

 
 
5.
#include<stdio.h>
 
int main(){
 
 unsigned int a = 0xFFFFFFF7;
 unsigned char i = (unsigned char)a;
 char* b = (char *)&a;
 printf("%08x,%08x",i,*b);//8位16进制数
 return 0;
}

 

结果与分析:
&a指的是a的地址,a是unsigned int类型。
所以char* b = (char *)&a;相当于
unsigned int* p = &a;
char* b = (char *) p;
 
6.
int f(int x,int y){
    return (x&y) + ((x^y)>>1);
}
(729,271) = 500
解析:
好精妙的题目。真的是应该好好掌握位运算。融会贯通。
x&y : x、y位与运算,相当于是相同的位只取了一次。
(x^y)>>1 : x、y异或相当于是不同的位全取。再右移>>相当于除2了。
所以两个运算都是取一半,综合起来就是取x、y的均值了。
扩展:用位运算求两个数的和?
int sum(int x,int y){
 return ((x&y<<1) + (x^y));
}
 
7.
判断两个数的大小?不用if、?:、switch等判断语句。
#include<iostream>
#include<cmath>
using namespace std;
 
int main(){
 
 int a =0,b = 0;
 cin>>a>>b;
 int c = a - b;
 char*strs[2] = {"a Large","b Large"};
 c = unsigned(c) >> (sizeof(int) * 8 - 1);
 cout<<strs[c]<<endl;
 int max = ((a + b) + abs(a - b))/2;
 cout<<max<<endl;
 return 0;
}

 

结果与分析:
第一种是通过比较符号位是0还是1还确定的。
第二种是通过简单的计算。
 

8.
题目:不用sort,整数操作尽可能少。求三个数的中间数。
#include<iostream>
using namespace std;
 
inline int max(int a,int b){
 return a>=b?a:b;
}
inline int min(int a,int b){
 return a<=b?a:b;
}
inline int medium(int a,int b,int c){
 
 int t1 = max(a,b);
 int t2 = max(b,c);
 int t3 = max(a,c);
 return min(t1,min(t2,t3));
}
int main(){
 
 cout<<medium(1,2,3);
 return 0;
}

 

结果与分析:
假设结果是T,先max操作,确保一定有1个数字比T小,然后min操作,确保一定有1个数字比T大。
一共就3个数字,所以一定是中间数。
 
9.
不使用中间变量,交换a、b的值。
#include<iostream>
 
using namespace std;
int main(){
 
 int a = 0,b = 0;
 cin>>a>>b;
 a = a + b;//可能会越界,如果a、b都比较大的话!
 b = a - b;
 a = a - b;
 cout<<a<<" "<<b<<endl;
 a = a ^ b;
 b = a ^ b;
 a = a ^ b;
 cout<<a<<" "<<b<<endl;
 return 0;
}

 

结果与分析:
我只想到第一种方法。更好的方法是用异或操作来做。
 
10.
一些概念性的问题:
switch中如果default放在开头,而下面可以匹配,则会跳过default。
如果default放在最后,不管咋样,都会default。
#include<iostream>
using namespace std;
 
int main(){
 
 int n = 'c';
 switch(n++){
 
  default:printf("error");break;
  case 'a':case 'A':case 'b':case 'B':printf("ab");break;
  case 'c':case 'C':printf("c");
  case 'd':case 'D':printf("d");
 }
 return 0;
} 

 

 
题目:c++调用c编译器编译后的函数,要加extern "C"
 
因为c++ 支持重载,所以编译后在库中的名字与C中的不一样,比如void foo(int x,int y)在c中是_foo,而在C++中
可能是_foo_int_int这种名字。
 
编程题目的细节!!!!!!!!!!!!!!!double还是int?除0?取整?考虑全面!
 

 
 

 

posted @ 2015-03-27 14:47  Qin&Yang  阅读(255)  评论(0编辑  收藏  举报