《程序员面试宝典》第3版大量错误纠正表

来源:互联网 发布:天下3男号捏脸数据 编辑:程序博客网 时间:2024/04/29 01:24

http://blog.csdn.net/hilyoo/article/details/4466680

《程序员面试宝典》第3版大量错误纠正表

       以前随手翻了翻,想写这篇文章没有写,现在完整看了下就记录下来了。找工作的同学大部分都会看《程序员面试宝典》,本来看过去就可以了。但我还是要把自己记录的大量错误指出来,以免误人子弟。这本书错误漏洞百出,编辑质量太差。虽然它一版再版,一再流传,却没有一个勘误表,错误改了很多,还有很多依然存在。

       因此提醒读者一定要自己动脑筋,否则很多错误的表述和观念植根于你的脑海,可能引起很严重的后果。而且,这本书功利性太强,属于快餐式知识,浮于表面,对自己的思想和观念都可能造成错觉。例如说序言,没错,是序言,涉世不深的朋友可能没看出玄机,没看出一个华丽的营销。你把序言翻到第二页,会看到一个偌大的签名,紧跟着偌大的MicroSoft的标记,以及一长串的签名和职位,没错,差不多一页了。这一大堆职位可能会给涉世不深的朋友很多错觉,正如“我在加州理工学院读书,然后获博士学位”仅仅指就在加州转了一圈,然后在野鸡大学拿了个博士文凭一样。

       当然,我不否认这本书的意义,它蜻蜓点水式地浏览了一下面试可能遇到的问题,可以帮助回顾自己需要掌握哪些知识。所以,下面把自己随手记录的50个左右的错误列出来,仅供大家参考,还有一些没有发现或者没有考虑或者懒得写出来,欢迎补充和交流(Kayven,hilyhoo@gmail.com)。

C/C++程序设计部分

这部分主要是语言概念的理解、细节、常见应用和一些经验技巧。

P38,5.5节 面试例题1

       解析过程表达和逻辑错误,没有说明结果是250的真正原因。“最后的结果应该是2,但在vs2008结果居然是250”说法牵强无逻辑,任何一个C++的程序的结果是理论上就确定的(包括未定义也是一种答案,由编译器实现也是一种确切的回答。比如局部变量int i没有初始化,那么它的值是未定义的,不会因为编译器是什么就是什么;比如 sizeof(int)的大小是由编译器和机器决定的,不能说因为编译结果是4就是4),不会因为编译器怎样就是什么结果;如果语言没定义就叫没定义,如果由编译器实现就是编译器实现而定,不会说因为编译器的结果是怎样的,就该是怎样的。C/C++语言本身是自完备的、自兼容的、自表达的。

       本题是这样的,~a操作时,会对a进行整型提升,a是无符号的,提升时左边补0(一般机器32位,char是8位,左边24个1;16位int则左边补8个0),取反后左边为1,右移就把左边的1都移到右边(注意是算术移位),再按照无符号读取,才有250这个结果。

P39,5.5节 面试例题3

       “这个的结果是x和y相同位的一半”,结果是相同位,也就是相同位的和的一半。

P40,5.6节 面试例题1

       方案一中,a-b可能溢出,这个应该需要提出,方案二同样,如果考虑溢出该怎么做?可以做相关判断,或者考虑位运算结合布尔逻辑数学公式、布电这类的方法。

P41,5.7节 面试例题2

       “头文件ifndef/define/endif干什么用的”,准确的说,它是条件编译的一种,除了头文件被防止重复引用(整体),还可以防止重复定义(变量、宏或者结构)。

P43,5.8节 面试例题

       去掉C/C++里的注释。1)单引号里有注释的情况是不可能的,当然这个对结果没影响。2)程序只考虑了引号前面是\的情况,如果是两个\,即反斜杠转义了就会出错。3)没有考虑到换行连接符的情况,如果有换行连接符也出错。

P45,6.1节 面试例题1

       宏定义#define FIND(struc,e) (size_t)&((((struc*)0)->e),后面跟了运算符就会出错的,另外题目的代码太糟糕了。

P47,6.2节 面试例题1

       C语言中,const修饰只读变量,而不是常量,题目解析与C++混淆了。这是一个概念理解性的错误。只有enum和#define才定义常量的。

P47,6.2节 面试例题2

       C++不允许没有类型的声明。

P47,6.2节 面试例题3

       并不是在const成员函数中用mutable修饰符,是对成员变量用mutable,const成员函数才可以修改。

P48,6.3节 面试例题1

       解析混乱,表达晦涩,一大篇解析没有抓住重点。如“a1、a2、a3是两个字节,结构体对齐参数按默认的8字节对齐,则a1、a2、a3都取2字节对齐”。应该是VC中,结构体按照其中元素字节数最长的对齐,相邻的元素可以连续放置(如果特殊优化可能调整顺序)。通俗但不完整的说,让每个元素可以一次读取即可。但GCC编译器默认都是4字节对齐,而且最大就是4字节的。

P56,6.3节 面试例题7

       1)sizeof(string)没有规定大小的,解析中给出的4是一种实现而已。2)size0f(*p)*2/sizeof(string),这种代码简单问题复杂化,*p是string类型的,已知了数组大小,而且硬编码到这里了,所以再用数组大小除以单个string大小让人费解。

P59,6.4节 面试例题9

       内联函数由编译器决定是否嵌入的,不是强制性的。主要优点是类型检查和可读性、可调试。重要的一点是只对参数做一次求值,而不像宏替换,这防止宏常出现的多次运算的错误。另外,注释里的“没有写返回值的”思路混乱,杂糅,不是体现内联与宏的区别。

P61,7.1节 面试例题1

       不是因为要变量不为空就要使用引用,没有这种因果关系。只是因为引用可以不做检查,更主要的是体现在指向的变量可变不可变和两者含义、作用不同。

P67,7.2节 面试例题3

       char *c不是分配一个全局数组,后面的字符串常量编译时已经分配,c是分配一个指针变量,它在栈上。

P72,7.3节 面试例题1

       Const指针和指向const的指针的区别。

P70,7.2节 面试例题7

       1)“B类的_a把A类的_a覆盖了”这种说法错误,注意基类与派生类的变量的作用域。这里可以说隐藏,但不是覆盖。2)构造B类对象,先调用A的构造函数,所以A类的_a为1,B类的_a为2,没有解析所说的因果关系。

P83,8.2节 面试例题1

       1)代码太混乱,递归还用了2层循环。使用了差不多一页2栏的代码。2)解析与代码无关,没有构造多叉树,只是循环比较而已。3)没有用const,参数太多。可以参考我的例子。

[cpp] view plaincopy
  1. /*************************************************************** 
  2. ** Contact: Kayven <hilyhoo@gmail.com> 
  3. ***************************************************************/  
  4. #include <iostream>  
  5. #include <vector>  
  6. using namespace std;  
  7.   
  8. static vector<int> pos_in_str;  
  9. void find_sub_link(const char* p1, const char* p2, int i, int j)  
  10. {  
  11.     if( !p1[i] || !p2[j] )  
  12.         return;  
  13.     if( p2[j]==p1[i] && !p2[j+1] ) {  
  14.         for(vector<int>::iterator it = pos_in_str.begin(); it != pos_in_str.end(); it++) {  
  15.             cout << *it << " ";  
  16.         }  
  17.         cout << i+1 << endl;  
  18.     }  
  19.     else if (p2[j] == p1[i]) {  
  20.         pos_in_str.push_back(i + 1);  
  21.         find_sub_link(p1, p2, i + 1, j + 1);  
  22.         pos_in_str.pop_back();  
  23.     }  
  24.     find_sub_link(p1, p2, i + 1, j);  
  25. }  
  26. int main(int argc, char **argv)  
  27. {  
  28.     char str1[10] = "abdbcca";  
  29.     char str2[10] = "abc";  
  30.     find_sub_link(str1, str2, 0, 0);  
  31.     return 0;  
  32. }  


P85,8.2节 面试例题3

       题目太混乱了,就是计算这个程序供调用多少次x(int n),不是设计算法。解析中,“单计算x(x(9))当然是9”太敷衍。

P87,8.3节 面试例题2

       int **a=(int*)malloc(N* sizeof(int))混淆了int和int1,虽然结果可能是一样的,但逻辑错误。sizeof(int)与sizeof(int *)含义不一样的。

P88,8.3节 面试例题3扩展

       所列的算法对结果几乎无改进,仅仅改成了一半的比较而已。这题的确需要结合快速排序和二分查找的思路,但可以改变时间复杂度的(给出的算法并没有改变)。

P92,8.5节 面试例题1

       代码中RAND_MAX* RAND_MAX越界了,考虑这个溢出,代码的结果应该是500左右。

P94,9.1节 面试例题1

       文不对题,距离实现vector,这只是使用vector而已。

P96,9.1节 面试例题3

       代码弄了一堆迭代器没有用到,很多例子这种情况,比网上拷贝粘贴的代码的排版还乱。

P98,9.2节 面试例题3

       1)T* array需要const,漏掉了。2)T n,n不是T类型的,应为int。

P105,10.2节 面试例题2

“Test b()是不正确的,因为它不需要预先赋值“,什么地方赋值了,什么叫预先赋值,什么叫不需要预先赋值。解析很让人纠结。

P108,10.3节 面试例题4

A(){const int size = 9;}这个时候,size不是成员变量了,改变了题意。

P115,10.5节 面试例题4

“B选项在gcc测试可以算是一种多态“,这种表述很多,模棱两可,说明理解不到位。由于返回类型协变,返回类指针可以不一样的,所以这个就是多态,不叫”算是“,也不是”gcc下算作“。

P120,10.7节 面试例题1

       构造函数x(a,b)应为x(a),y(b)

P125,11.2节 面试例题1

       翻译太差,解析了几页没有说清楚。自己理解意思即可。

D选项,不能被派生类的子类访问。

B选项,都可以继承,只是不能访问。

P130,11.3节 面试例题1

       自己说了不需要链表,还选择B。而且,不是每个对象都有一个表,多重继承可以多个,在VC里虚继承也有多个。

P131,11.3节 面试例题2

(2)(3)的解析混乱且有错误,虽然答案是那样的。首先,与编译器有关。其次,解析中,(2)是多了数组和虚类指针,不是多了虚函数表指针。

P135,11.4节 面试例题4

       PB实际的地址是C父类B部分,不是子类。

P144,11.7节 面试例题2

       一大堆没用的描述,没有指出重点。这个题是转换函数的问题。它是一种特殊的运算符重载,特殊的成员函数,无返回类型,无参数,一般最好用const修饰。

P135,11.4节 面试例题4


数据结构与算法部分,几乎所有代码都没有认真编辑、校验和核对。排版及其混乱,变量名、函数名很山寨,程序逻辑漏洞百出,没用的代码一大堆。这些低级的我就不一一列举了。几个主要的错误如下:

P167,13.1节 面试例题1

       node *create()里malloc了head,没有释放。多余的操作很多,如while前面的if没用。

P167,13.1节 面试例题2

       P1为NULL没有判断,链表头与链表节点混淆使用。

P167,13.1节 面试例题7

       这部分代码基本都是粗制滥造,大量无关代码,NULL判断不足,变量未使用,未释放malloc的空间。

P224,14.3节 面试例题3

       第257个char才是ch,解析错误。结果与256、257之类的没关系。因为127+1为负数了小于255,所以一直循环。不是什么改变256个char的值。

P225,14.4节 面试例题2

       B显然错误,C中即使加了const也不行,题目是要求C语言中。只有C++才可以。

P226,14.5节 面试例题2

       程序输出的是所以重复出现的而不是长度最长的,这样的错误很多。

P228,14.5节 面试例题5

       代码竟然写了一页半。可以参考一下我的代码。当然也不一定非常好,欢迎指正(Kayven,hilyhoo@gmail.com)

[cpp] view plaincopy
  1. /*************************************************************** 
  2. ** Contact: Kayven <hilyhoo@gmail.com> 
  3. ***************************************************************/  
  4. #include <stdio.h>  
  5. unsigned long f(unsigned long n){  
  6.     unsigned long fn = 0, ntemp = n;  
  7.     unsigned long step;  
  8.     for(step = 1; ntemp > 0; step *= 10, ntemp /= 10){  
  9.         fn += (((ntemp -1 ) /10) + 1) * step;  
  10.         if(( ntemp % 10 ) ==1){  
  11.             fn -= step - (n % step + 1);  
  12.         }  
  13.     }  
  14.     return fn;  
  15. }  
  16. unsigned long get_max_fn_equal_n(unsigned long upper_bound){  
  17.     unsigned long n = 1, fn = 0;  
  18.     unsigned long max = 1;  
  19.     while(n <= upper_bound ) {  
  20.         fn = f(n);  
  21.         if(fn == n){  
  22.             max = n;  
  23.             printf("%10lu\t" , n++);  
  24.         }  
  25.         else if( fn < n )  
  26.             n += (n-fn)/10 + 1;  
  27.         else   
  28.             n = fn;   
  29.     }  
  30.     return max;  
  31. }  
  32. int main()  
  33. {  
  34.     unsigned long upper_bound = 4000000000UL;  
  35.     printf("[::test] f(%lu) = %lu.\n", 13, f(13));  
  36.     printf("\n[::max] max({f(n)=n, n<=%lu}) = %lu.\n", upper_bound, get_max_fn_equal_n(upper_bound));  
  37.     return 0;  
  38. }  


P230,14.6节 面试例题

       1)strlen(reschar)并不是当前字符串长度,因为只有rescahr[0]置为’\0’,后面的并没有清空,所以代码的结果未知。可以使用memset清空。2)题中代码使用了C++,所以使用cou即可,解答大量混淆C与C++代码,风格很差。并不像题目所说,用sprintf才行。3)if str[k]=str[k+1]count++;错误,这一部分不需要,只需要循环到len-2即可。

       还有很多就不提了,这是一本营销出来的书,自己多思考多实践会有一些用。如果死记这本书的一些观点和解析只会有害无益。这里把错误列出来也是给大家参考,可能还有我没有发现的或者没有其它观点,欢迎补充。