2023年軟體面試問題總結

2021-05-08 14:00:19 字數 4691 閱讀 5689

主要的區別由以下幾點:

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種分配方式:

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

分配效率:棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。

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

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

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

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

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

還有如下的解釋:

堆(heap)和棧(stack)有什麼區別??

簡單的可以理解為:

heap:是由malloc之類函式分配的空間所在地。位址是由低向高增長的。

stack:是自動分配變數,以及函式呼叫的時候所使用的一些空間。位址是由高向低減少的。

一般我們常說的記憶體洩漏是指堆記憶體的洩漏。堆記憶體是指程式從堆中分配的,大小任意的(記憶體塊的大小可以在程式執行期決定),使用完後必須顯式釋放的記憶體。應用程式一般使用malloc,calloc,realloc,new等函式從堆中分配到一塊記憶體,使用完後,程式必須負責相應的呼叫free或delete釋放該記憶體塊,否則,這塊記憶體就不能被再次使用,我們就說這塊記憶體洩漏了。

記憶體溢位就是你要求分配的記憶體超出了系統能給你的,系統不能滿足需求,於是產生溢位。

比方說棧,棧滿時再做進棧必定產生空間溢位,叫上溢,棧空時再做退棧也產生空間溢位,稱為下溢。

1. static全域性變數與普通的全域性變數有什麼區別 ?

全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。

全域性變數本身就是靜態儲存方式, 靜態全域性變數當然也是靜態儲存方式。 這兩者在儲存方式上並無不同。

這兩者的區別在於非靜態全域性變數的作用域是整個源程式, 當乙個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。 而靜態全域性變數則限制了其作用域, 即只在定義該變數的原始檔內有效, 在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於乙個原始檔內,只能為該原始檔內的函式公用,因此可以避免在其它原始檔中引起錯誤。

static全域性變數只初使化一次,防止在其他檔案單元中被引用;

2. static區域性變數和普通區域性變數有什麼區別 ?

把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域,限制了它的使用範圍。

static區域性變數只被初始化一次,下一次依據上一次結果值;

3. static函式與普通函式有什麼區別?

static函式與普通函式作用域不同,僅在本檔案。只在當前原始檔中使用的函式應該說明為內部函式(static修飾的函式),內部函式應該在當前原始檔中說明和定義。對於可在當前原始檔以外使用的函式,應該在乙個標頭檔案中說明,要使用這些函式的原始檔要包含這個標頭檔案.

static函式在記憶體中只有乙份,普通函式在每個被呼叫中維持乙份拷貝

三、海量資料處理系列——c語言下實現bitmap演算法

題目中所說的是定義而不是宣告,也就不可能是extern的宣告方式了,定義的話會有記憶體分配,如果這個標頭檔案包含在多個.c檔案中則涉及到重複定義,這樣生成的obj檔案中可能會有多個該全域性變數的拷貝,這樣連線的話可能報錯。

這裡沒有說是不是static的全域性變數,所以我們假設不是(如果可以static的話這個問題就沒有意義了)。

如果是指變數的宣告和定義:

從編譯原理上來說,宣告是僅僅告訴編譯器,有個某型別的變數會被使用,但是編譯器並不會為它分配任何記憶體。而定義就是分配了記憶體。

對於下面的兩句**:

void func()

對於第一行**,編譯器不會做任何事,它不會為它在棧中分配一點東西,直到第三句,a=0;時,編譯器才會將其壓入棧中。而對於int b=0;這一句,編譯器就會生成一條指令,為它賦值。如果反彙編,看到的**可能是這樣的:

push 1;

push 0;

當然,並不一定編譯器就會樣做,也有可能在宣告int a時,編譯器就會把乙個廢值入棧,到第三條再為其賦值,這要看編譯器的具體取捨,所以,宣告不一定不是定義,而定義一定是定義。

但是,下面的宣告,一定僅僅是宣告:

extern int a;

這錶時,有乙個int變數a,它一定是在另外其他地方定義的,所以編譯器此時一定不會做什麼分配記憶體的事,因為它就是宣告,僅僅表明下面的**引用了乙個符號,而這個符號是int型別的a而已。

如果是指函式的宣告和定義:

宣告:一般在標頭檔案裡,對編譯器說:這裡我有乙個函式叫function() 讓編譯器知道這個函式的存在。

定義:一般在原始檔裡,具體就是函式的實現過程寫明函式體。

問題一:關於巨集這個的確是可以解決重複定義問題,下面這段**就可以避免一些變數被重複定義。

#ifndef max

#define max

..../*定義一些你要定義的變數*/

#endif

複製**

問題二:在.h檔案中定義全域性變數但不初始化,這樣可以編譯通過,那是因為沒有初始化的全域性變數是弱符號,初始化後是強符號

1.編譯時不分配記憶體

編譯時是不分配記憶體的。此時只是根據宣告時的型別進行佔位,到以後程式執行時分配記憶體才會正確。所以宣告是給編譯器看的,聰明的編譯器能根據宣告幫你識別錯誤。

2.執行時必分配記憶體

執行時程式是必須調到「記憶體」的。因為cpu(其中有多個暫存器)只與記憶體打交道的。程式在進入實際記憶體之前要首先分配物理記憶體。

3.編譯過程

只能簡單說一下,因為如果要詳細的話,就是一本書了《編譯原理》。編譯器能夠識別語法,資料型別等等。然後逐行逐句檢查編譯成二進位制資料的obj檔案,然後再由鏈結程式將其鏈結成乙個exe檔案。

此時的程式是以exe檔案的形式存放在磁碟上。

4.執行過程

當執行這個exe檔案以後,此程式就被載入到記憶體中,成為程序。此時一開始程式會初始化一些全域性物件,然後找到入口函式(main()或者winmain()),就開始按程式的執行語句開始執行。此時需要的記憶體只能在程式的堆上進行動態增加/釋放了。

1、程式**區:存放函式體的二進位制**。

2、全域性區(靜態區)(static):全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。 程式結束後由系統釋放。

3、文字常量區 :常量字串就是放在這裡的。 程式結束後由系統釋放。

4、堆區(heap): 一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由os** 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於鍊錶。

5、棧區(stack):由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。

1 基本解釋  extern可以置於變數或者函式前,以標示變數或者函式的定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找其定義。

另外,extern也可用來進行鏈結指定。

面試問題總結

2.不要說自己有那些庸俗的 令人感覺不好的愛好。3.最好不要說自己僅限於讀書 聽 上網,否則可能會令面試官懷疑應聘者性格孤僻。4.最好能有一些戶外的業餘愛好來 點綴 你的形象。選擇答案 b 我的愛好比較廣泛,只要是年輕人喜歡的活動我都喜歡參加,並積極組織,在活動中,我們學到了各類知識。c 我的業餘愛...

面試問題總結

以後想從事什麼方面的工作 只要涉及到到以後工作的問題,一定要突出會回國的打算 3,資金情況 你是否已經交了學費 你假期準備做什麼 盡量不要提假期打工,因為打工會給簽證官資金不足的印象。誰來承擔你的學費和生活費 你會在假期打工麼 你父母是做什麼工作的,收入多少 如果父母收入比較低,一年的收入不能支付學...

面試問題總結

一 常規問題 1.請作下自我介紹,時間控制在兩分鐘左右 2.為什麼選擇我們公司,請說說你對我們公司的了解 3.你覺得你自身哪些特點使你適合在我們公司工作 4.你認為你進入我們公司後能夠負責哪些方面的工作,因為什麼 5.請你全面的評價下你自己,並且說出自己至少三個優點三個缺點 6.請你說說你心目中優秀...