天天看點

筆試面試經典問題

const和#define的差別:

1. 編譯器處理方式不同

define宏是在預處理階段展開。

const常量是編譯運作階段使用。

2. 類型和安全檢查不同

define宏沒有類型,不做任何類型檢查,僅僅是展開。

const常量有具體的類型,在編譯階段會執行類型檢查。

3. 存儲方式不同

define宏定義不占記憶體

const常量會在記憶體中配置設定(可以是堆中也可以是棧中)。

4. const常量有适當的作用域,而宏常量的作用域是全局的,也就是說宏常量不具有封裝性。

5. const常量可以取位址,宏常量不可以取位址。

const作用

在c++中,const是類型修飾符。

1. 使用const修飾的變量,值不能被更改;

2. const還可以修飾函數參數、函數傳回值和函數本身;

3. 函數可以根據是否為const進行重載;

類中const成員初始化:

       在初始化清單中初始化。

static作用

static用來控制變量的存儲方式和可見性。

1. static變量存儲在程式的靜态存儲區。(函數執行結束不會釋放存儲空間)

2. static把變量的可見範圍限制在編譯單元中,使它成為一個内部連結。

總結:

       static總是使得變量或對象的存儲形式變成靜态存儲,連結方式變成内部連結。對于局部變量(已經是内部連結了),它僅改變其存儲方式;對于全局變量(已經是靜态存儲了),它僅改變其連結類型。

類中的static成員:

       static成員和類相關,而不是和類的對象相關。

項目中有沒有用過static?

全局變量、靜态全局變量、靜态局部變量:

       當一個源程式由多個源檔案組成時,非靜态的全局變量在各個源檔案中都是有效的。而靜态全局變量隻在定義該變量的源檔案内有效,在同一源程式的其他源檔案中不能使用它。 (把局部變量改變為靜态變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜态變量後是改變了它的作用域,限制了它的使用範圍。)

static成員初始化:

static成員必須在類定義體的外部定義,而且應該在定義時初始化。但是,整形const static資料成員就可以在類的定義體中進行初始化。

函數局部static變量初始化:

       c++中,在第一次用到時才會被初始化(lazy initialization)。

全局static變量的初始化在編譯的時候進行。

extern關鍵字:

C和C++對函數的處理方式(名稱修飾)是不同的.extern "C"是使C++能夠調用C寫作的庫檔案的一個手段,如果要對編譯器提示使用C的方式來處理函數的話,那麼就要使用extern "C"來說明。

volatile關鍵字:

volatile的本意是“易變的”,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如作業系統、硬體或者其它線程等。關鍵字volatile是給編譯器的訓示,指出對這樣的對象不應該執行優化。

volatile基本可以做到兩件事情:

1. 阻止編譯器為了提高速度将一個變量緩存到寄存器内而不寫回。

2. 阻止編譯器調整操作volatile變量的指令順序。

模闆和宏的差別:

1. 模闆是類型安全的,宏不是。

2. 宏在預編譯階段直接展開,而模闆隻有在用到時才執行個體化。

3. 模闆的功能更加強大,支援偏特化、支援模闆元程式設計。

指針和引用的差別:

1. 指針是一個實體,在邏輯上是獨立的;引用是個别名,在邏輯上不是獨立的

2. 指針可以為空,引用不可以為空

3. 引用需要初始化,指針不需要

4. 指針可以被重新指派,而引用總是指向最初的對象

(引用在語言内部是用指針實作的,引用就是一個常量指針,當然也占記憶體)

C 中指針和引用的實體實作是一回事,都是記憶體位址;兩者的差別是在編譯時編譯器無法對指針操作進行類型檢查,而對引用可以。這也是引用更安全的原因。

引用是類型安全的,而指針不是

引用傳遞與指針傳遞的差別?

指針傳遞參數的本質是值傳遞,引用的任何操作都處理成間接尋址

堆和棧的差別:

1. 空間配置設定

       棧:由作業系統自動配置設定釋放

       堆:一般由程式員配置設定釋放

2. 棧的存取速度快

3. 棧是一塊連續的記憶體區域。堆是不連續的記憶體區域。

4. 堆獲得的空間比較靈活,也比較大。

【棧中存放的内容:

1. 函數傳回位址、函數參數

2. 函數局部變量

3. 上下文:比如函數調用前後需要保證不變的寄存器值】

memcpy和memmove函數的差別?

void * memcpy (void * dest, const void *src, size_t n);

void * memmove(void *dest, const void *src, size_t n);

作用都是從源記憶體拷貝n個位元組到目标記憶體。不同的是,當源記憶體和目标記憶體發生重疊時,memcpy會出現錯誤,而memmove能正确地實施拷貝,但這也增加了一點點開銷。

new/delete和malloc/free的差別:

1. malloc是标準庫函數,new是c++運算符,它們都可用于申請動态記憶體。

2. 對于非内部資料類型的對象而言,對象在建立的同時要自動執行構造函數。malloc無法滿足要求,而new可以完成動态記憶體配置設定和初始化工作。

3. new自動計算需要配置設定的空間,而malloc需要手工計算。

4. new是類型安全的,而malloc不是。

5. malloc需要頭檔案支援,new不需要。

6. new在實作上其實調用了malloc函數。

重載(overload)、覆寫(override) = 重寫、隐藏(hide)的差別:

重載:

         1. 相同作用域(在同一個類中);

         2. 名字相同;

         3. 形參表不同;

覆寫:(派生類函數重寫基類函數)

         1. 不同作用域(分别位于基類與派生類);

         3. 形參表相同、傳回值相同;

         4. 基類函數必須有virtual關鍵字;

隐藏:(派生類函數屏蔽基類函數)

         1. 派生類函數與基類函數名字相同、形參表不同,不論有無virtual關鍵字,基類函數将被隐藏。

         2. 派生類函數與基類函數名字相同、形參表相同,但是基類函數無virtual關鍵字,基類函數将被隐藏。

深拷貝(deep copy)與淺拷貝(shallow copy)的差別:

如果一個對象擁有資源,複制對象時連同對象擁有的資源一起複制,就是深拷貝,沒有複制對象擁有的資源就是淺拷貝。

淺拷貝也稱位拷貝。

預設的拷貝構造函數和指派操作符進行的都是淺拷貝。

淺拷貝缺點:

         多個對象指向一塊記憶體,當某個對象釋放記憶體後,其他指向這塊記憶體的對象就會出錯。

當資料成員中有指針時,必須使用深拷貝。

string三種實作方式:

1. 直接拷貝(eager copy)

2. Copy-on-Write(COW,寫時複制)

       Copy-On-Write一定使用了“引用計數”

基于”共享“和”引用“計數的COW在多線程環境下必然面臨線程安全的問題。

"The COW is dead, long live eager-copy"

3. 短字元串優化(SSO, Short String Optimization)

http://www.cnblogs.com/promise6522/archive/2012/03/22/2412686.html

數組、連結清單、hash的差別:

1. 數組中的元素在記憶體中是連續存儲的,連結清單中的元素在記憶體中不是連續存儲的。

數組支援随機存取,查找效率高,但插入、删除效率低。連結清單查找效率低,但插入、删除效率高。

2. 數組必須事先定義固定的長度,不能适應資料動态增減的情況。

有什麼方式既能夠具備數組的快速查詢的優點又能融合連結清單友善快捷的增加删除元素的優勢?HASH呼之欲出。

hash表處理沖突:

1. 開放位址法:

       線性探測再散列、二次探測再散列、僞随機探測再散列

2. 再哈希法

3. 鍊位址法

一緻性hash:

一緻性hash算法的主要目的是為了盡量減少資料遷移

每天進步一點點——五分鐘了解一緻性雜湊演算法(consistent hashing)

查找:

順序查找、二分查找、二叉排序樹查找、哈希表查找、分塊查找

——————————————————————————————————————

繼續閱讀