C 面試常見問題總結(不斷更新中 )

2021-08-02 10:09:21 字數 2683 閱讀 6417

1.記憶體洩漏

指由於疏忽或錯誤造成程式未能釋放已經不再使用的記憶體的情況。記憶體洩漏並非指內存在物理上的消失,而是應用程式分配某段記憶體後,由於設計錯誤,失去了對該段記憶體的控制,因而造成了記憶體的浪費。

2.虛析構函式

c++中不允許使用虛建構函式,但是可以使用虛析構函式。析構函式設定為虛函式之後,在使用指標引用時可以動態繫結,實現執行時的多型,保證使用基類型別的指標就能夠呼叫適當的析構函式針對不同的物件進行清理工作。(c++不允許使用虛建構函式原因:虛函式採用的是一種虛呼叫的方法,虛呼叫是一種可以只有部分資訊的情況下工作的機制,如果建立乙個物件,則需要知道物件的準確型別,因此,建構函式不能為虛函式!)

3.c/c++記憶體管理

(1)棧

棧就是那些由編譯器在需要的時候分配,在不需要的時候自動清除的變數的儲存區。裡面的變數通常是區域性變數、函式引數等。在乙個程序中,位於使用者虛擬位址空間頂部的是使用者棧,編譯器用它來實現函式的呼叫。

(2)堆

堆就是那些由 new 分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般乙個 new 就要對應乙個 delete。如果程式設計師沒有釋放掉,那麼在程式結束後,作業系統會自動**。堆可以動態地擴充套件和收縮。

(3)自由儲存區

自由儲存區就是那些由 malloc 等分配的記憶體塊,他和堆是十分相似的,不過它是用 free 來結束自己的生命的。

(4)全域性/靜態儲存區

全域性變數和靜態變數被分配到同一塊記憶體中,在以前的 c 語言中,全域性變數又分為初始化的和未初始化的(初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數與靜態變數在相鄰的另一塊區域,同時未被初始化的物件儲存區可以通過 void* 來訪問和操縱,程式結束後由系統自行釋放),在 c++ 裡面沒有這個區分了,他們共同占用同一塊記憶體區。

(5)常量儲存區

常量儲存區,這是一塊比較特殊的儲存區,他們裡面存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改,而且方法很多)。

4.堆與棧的區別

(1)管理方式不同;

(2)空間大小不同;

(3)能否產生碎片不同;

(4)生長方向不同;

(5)分配方式不同;

(6)分配效率不同;

管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程式設計師控制,容易產生memory leak。

空間大小:一般來講在 32 位系統下,堆記憶體可以達到4g的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的,例如,在vc6下面,預設的棧空間大小是1m(好像是,記不清楚了)。當然,我們可以修改:開啟工程,依次操作選單如下:project->setting->link,在 category 中選中 output,然後在 reserve 中設定堆疊的最大值和 commit。注意:reserve 最小值為 4byte;commit 是保留在虛擬記憶體的頁檔案裡面,它設定的較大會使棧開闢較大的值,可能增加記憶體的開銷和啟動時間。

碎片問題:對於堆來講,頻繁的 new/delete 勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以至於永遠都不可能有乙個記憶體塊從棧中間彈出,在他彈出之前,在他上面的後進的棧內容已經被彈出,詳細的可以參考資料結構,這裡我們就不再一一討論了。

生長方向:對於堆來講,生長方向是向上的,也就是向著記憶體位址增加的方向;對於棧來講,它的生長方向是向下的,是向著記憶體位址減小的方向增長。

分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由 malloc 函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

分配效率:棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是 c/c++ 函式庫提供的,它的機制是很複雜的,例如為了分配一塊記憶體,庫函式會按照一定的演算法(具體的演算法可以參考資料結構/作業系統)在堆記憶體中搜尋可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於記憶體碎片太多),就有可能呼叫系統功能去增加程式資料段的記憶體空間,這樣就有機會分到足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

從這裡我們可以看到,堆和棧相比,由於大量 new/delete 的使用,容易造成大量的記憶體碎片;由於沒有專門的系統支援,效率很低;由於可能引發使用者態和核心態的切換,記憶體的申請,代價變得更加昂貴。所以棧在程式中是應用最廣泛的,就算是函式的呼叫也利用棧去完成,函式呼叫過程中的引數,返回位址,ebp 和區域性變數都採用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。

雖然棧有如此眾多的好處,但是由於和堆相比不是那麼靈活,有時候分配大量的記憶體空間,還是用堆好一些。

無論是堆還是棧,都要防止越界現象的發生(除非你是故意使其越界),因為越界的結果要麼是程式崩潰,要麼是摧毀程式的堆、棧結構,產生以想不到的結果,就算是在你的程式執行過程中,沒有發生上面的問題,你還是要小心,說不定什麼時候就崩掉,那時候 debug 可是相當困難的 :)

對了,還有一件事,如果有人把堆疊合起來說,那它的意思是棧,可不是堆,呵呵,清楚了?

不斷更新中 各種錯誤 總結

永遠不要把陣列大小卡的自認為太準確,能開就往大開 審的題意和考題題意不一樣 qwq 最大值設的不夠大 答案超過intqaq dp陣列沒有初始化 dp導致陣列越界re 直接輸出dp中的值 其實要利用dp值判斷最終答案 最小 大 生成樹 求解保證某 兩個點連通性 和 最小邊權最大 類似 的問題 最短路可...

不斷更新中 各種錯誤 總結

無論感覺多穩都要對拍對拍對拍 不要爆long long 不要爆long long 不要爆long long 不要爆long long 不要爆long long 不要爆long long 不要爆long long 二維st表注意邊界 見模板 連續lcm不可模 兩個指標注意只有左指標對應值不變時,右指標...

C語言中的常見問答 不斷更新中

1,c語言之所以能存在和發展,並具有較強的生命力,主要是因為有如下特點 1,語言簡潔 緊湊,使用方便 靈活。c語言共有32個關鍵字,9種控制語句。2,運算子豐富。c語言共有34種運算子,把括號 賦值 強制型別轉換都作為運算子處理。3,資料型別豐富,具有現代語言的各種資料結構。4,具有結構化控制語句。...