C 入門題目小結

2021-06-26 12:14:34 字數 3839 閱讀 8996

一、簡述c++記憶體分配方式

c++中,記憶體分成

5個區,他們分別是堆、棧、自由儲存區、全域性

/靜態儲存區和常量儲存區。

1.棧,在執行函式時,

函式的引數級函式內區域性變數

的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。

2.堆,就是那些由

new分配的記憶體塊,他們的釋放編譯器不去管,由我們的

應用程式

去控制,一般乙個

new就要對應乙個

delete

。如果程式設計師沒有釋放掉,那麼在程式結束後,作業系統會自動**。

3.自由儲存區,就是那些由

malloc

等分配的記憶體塊,他和堆是十分相似的,不過它是用

free

來結束自己的生命的。

4.全域性

/靜態儲存區,

全域性變數

和靜態變數

被分配到同一塊記憶體中,在以前的

c語言中,全域性變數又分為初始化的和未初始化的,在

c++裡面沒有這個區分了,他們共同占用同一塊記憶體區。

5.常量儲存區,這是一塊比較特殊的儲存區,他們裡面存放的是常量,

不允許修改

二、簡述堆疊的區別

1.

管理方式

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

memory leak

。 2.

空間大小

:一般來講在

32位系統下,堆記憶體可以達到

4g的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的,例如,在

vc6下面,預設的棧空間大小是

1m(好像是,記不清楚了),不過我們可以修改。

3.碎片問題

:對於堆來講,頻繁的

new/delete

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

4.生長方向

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

5.分配方式

:堆都是動態分配的,沒有靜態分配的堆。棧有

2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由

alloca

函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

6.分配效率

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

c/c++

函式庫提供的,它的機制是很複雜的,例如為了分配一塊記憶體,庫函式會按照一定的演算法(具體的演算法可以參考資料結構

/作業系統)在堆記憶體中搜尋可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於記憶體碎片太多),就有可能呼叫系統功能去增加程式資料段的記憶體空間,這樣就有機會分到足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

從這裡我們可以看到,堆和棧相比,由於大量

new/delete

的使用,容易造成大量的記憶體碎片;由於沒有專門的系統支援,效率很低;由於可能引發使用者態和核心態的切換,記憶體的申請,代價變得更加昂貴。所以棧在程式中是應用最廣泛的,就算是函式的呼叫也利用棧去完成,函式呼叫過程中的引數,返回位址,

ebp和區域性變數都採用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆(分配大量的記憶體空間,還是用堆好一些)。

三、說說

malloc/free

為什麼還要

new/delete?

malloc

與free

是c++/c

語言的標準庫函式,

new/delete

是c++

的運算子。它們都可用於申請動態記憶體和釋放記憶體。

對於非內部資料型別的物件而言,光用

maloc/free

無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行析構函式。由於

malloc/free

是庫函式而不是運算子,不在編譯器控制許可權之內,不能夠把執行建構函式和析構函式的任務強加於

malloc/free。因此

c++語言需要乙個能完成動態記憶體分配和初始化工作的運算子

new,以及乙個能完成清理與釋放記憶體工作的運算子

delete

四、說說陣列與指標?

c++/c

程式中,指標和陣列在不少地方可以相互替換著用,讓人產生一種錯覺,以為兩者是等價的。

陣列要麼在靜態儲存區被建立(如全域性陣列),要麼在棧上被建立。陣列名

對應著(而不是指向)

一塊記憶體,其位址與容量在生命期內保持不變,只有陣列的內容可以改變。

指標可以隨時

指向任意型別

的記憶體塊,它的特徵是「可變」,所以我們常用指標來操作動態記憶體。指標遠比陣列靈活,但也更危險。

五、全域性變數、區域性變數、靜態全域性變數、靜態區域性變數的區別

c++變數根據定義的位置的不同的生命週期,具有不同的作用域,作用域可分為6種:全域性作用域,區域性作用域,語句作用域,類作用域,命名空間作用域和檔案作用域。 

1.從作用域看:

全域性變數具有全域性作用域。全域性變數只需在

乙個原始檔中定義,就可以作用於所有的原始檔

。當然,其他不包含全域性變數定義的原始檔需要用

extern

關鍵字再次宣告這個全域性變數。

區域性變數也只有區域性作用域,它是自動物件(auto),它在程式執行期間不是一直存在,而是只在函式執行期間存在,函式的一次呼叫執行結束後,變數被撤銷,其所占用的記憶體也被收回。

靜態區域性變數具有區域性作用域,它只被初始化一次,自從第一次被初始化直到程式執行結束都一直存在,它和全域性變數的區別在於全域性變數對所有的函式都是可見的,而靜態區域性變數只對定義自己的函式體始終可見。

靜態全域性變數也具有全域性作用域,它與全域性變數的區別在於如果程式包含多個檔案的話,它作用於定義它的檔案裡,不能作用到其它檔案裡,即被

static關鍵字修飾過的變數具有檔案作用域

。這樣即使兩個不同的原始檔都定義了相同名字的靜態全域性變數,它們也是

不同的變數。

2.從分配記憶體空間看:

全域性變數,靜態區域性變數,靜態全域性變數都在靜態儲存區分配空間,而

區域性變數在棧

裡分配空間。

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

1)、靜態變數會被放在程式的靜態資料儲存區(資料段)(全域性可見)中,這樣可以在下一次呼叫的時候還可以保持原來的賦值。這一點是它與堆疊變數和堆變數的區別。

2)、變數用static告知編譯器,自己僅僅在變數的作用範圍內可見。這一點是它與全域性變數的區別。

C入門題目

反轉乙個只有3位數的整數。樣例 1 輸入 number 123 輸出 321樣例 2 輸入 number 900 輸出 9 你可以假設輸入一定是乙個只有三位數的整數,這個整數大於等於100,小於1000。class solution 問題 1043 程式設計入門 三個數字的排序 題目描述 輸入三個整...

程式設計 C 入門C小結

現在我來對我將近兩周對c語言的學習來個小結,雖然程式設計正課教的c 但是講的.額,有點慢,起碼用來做那些題肯定不夠,那為什麼我要放著c 不學學c?因為一本被強勢推薦的教材.對於c來說吧,挺簡單,經過近兩周的學習的基本邏輯結構如迴圈結構什麼的已經沒什麼問題 大概 放個我認為很有用的慕課位址,很清楚 從...

Top K 題目小結

1.不管是一維陣列還是二維或多維陣列求第k小或第k大元素,如果陣列是無序的,那麼 求第k小的元素就用最大堆,求第k大的元素就用最小堆。如果是一維陣列,時間複雜度是o nlogk 如果是二維陣列,時間複雜度是o mnlogk 注意,這裡也可以是乙個鍊錶,或者m個鍊錶,做法一樣,時間複雜度也一樣。2.不...