《程式員面試寶典》第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,參數太多。可以參考我的例子。
/***************************************************************** Contact: Kayven <hilyhoo@gmail.com>***************************************************************/#include <iostream>#include <vector>using namespace std;static vector<int> pos_in_str;void find_sub_link(const char* p1, const char* p2, int i, int j){if( !p1[i] || !p2[j] )return;if( p2[j]==p1[i] && !p2[j+1] ) {for(vector<int>::iterator it = pos_in_str.begin(); it != pos_in_str.end(); it++) {cout << *it << " ";}cout << i+1 << endl;}else if (p2[j] == p1[i]) {pos_in_str.push_back(i + 1);find_sub_link(p1, p2, i + 1, j + 1);pos_in_str.pop_back();}find_sub_link(p1, p2, i + 1, j);}int main(int argc, char **argv){char str1[10] = "abdbcca";char str2[10] = "abc";find_sub_link(str1, str2, 0, 0);return 0;}
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
代碼竟然寫了一頁半。可以參考一下My Code。當然也不一定非常好,歡迎指正(Kayven,hilyhoo@gmail.com)
/***************************************************************** Contact: Kayven <hilyhoo@gmail.com>***************************************************************/#include <stdio.h>unsigned long f(unsigned long n){unsigned long fn = 0, ntemp = n;unsigned long step;for(step = 1; ntemp > 0; step *= 10, ntemp /= 10){fn += (((ntemp -1 ) /10) + 1) * step;if(( ntemp % 10 ) ==1){fn -= step - (n % step + 1);}}return fn;}unsigned long get_max_fn_equal_n(unsigned long upper_bound){unsigned long n = 1, fn = 0;unsigned long max = 1;while(n <= upper_bound ) {fn = f(n);if(fn == n){max = n;printf("%10lu\t" , n++);}else if( fn < n )n += (n-fn)/10 + 1;else n = fn; }return max;}int main(){unsigned long upper_bound = 4000000000UL;printf("[::test] f(%lu) = %lu.\n", 13, f(13));printf("\n[::max] max({f(n)=n, n<=%lu}) = %lu.\n", upper_bound, get_max_fn_equal_n(upper_bound));return 0;}
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即可。
還有很多就不提了,這是一本營銷出來的書,自己多思考多實踐會有一些用。如果死記這本書的一些觀點和解析只會有害無益。這裡把錯誤列出來也是給大家參考,可能還有我沒有發現的或者沒有其它觀點,歡迎補充。