c 動態記憶體管理

2022-08-16 00:36:17 字數 4261 閱讀 7043

一、記憶體的簡要了解

說到記憶體,很多人應該都多多少少有點了解了,我們在這再稍微多說幾句:

一般我們可以把記憶體理解為三個部分:靜態區,棧,堆。有些朋友搞不清到底什麼是棧什麼是堆,堆疊有多人會認為是堆和棧,兩個放在一塊。其實不然,其中我們口中講的堆疊就是棧,而不是堆。堆的英文是heap ;棧的英文是stack(也翻譯為堆疊)。

儲存內容:

靜態區:儲存自動全域性變數和static變數(包括static全域性和區域性變數)。靜態區的內容在整個程式的生命週期內都存在,有編譯器在編譯的時候分配(資料段(儲存全域性資料和靜態資料)和**段(可執行的**/唯讀常量))。

棧:儲存區域性變數。棧上的內容只在函式範圍內存在,當函式執行結束的時候,這些內容也會自動銷毀。其特點是效率高但是空間大小有限。

堆:由malloc系列函式或者new操作符分配的記憶體。其生命週期由free和delete決定。在沒有釋放之前一直存在,直到函式結束。其特點是使用靈活,空間比較大,但容易出錯。

我們用一張圖來簡單看下:

值得注意的一點是:**段中儲存的是可執行的**和唯讀常量,很多人看到**段就認為裡面只有**,資料段裡面才是儲存資料的,其實不是這樣的。

二、malloc、calloc、realloc

三者的簡單對比:

malloc   函式原型:(void*)malloc(unsigned size);(位元組數)

malloc函式在記憶體中開闢的是一塊連續的空間,size是所需要空間的長度,開闢的大小為size*引數型別,開闢完之後返回這塊空間的首位址。

calloc    函式原型:void* calloc(size_t numelements, size_t sizeofelements);(元素的個數, 單個元素的位元組數)

和malloc相似,它也是開闢一塊連續的空間,空間的大小為:元素的個數*單個元素的位元組數。

給乙個已經分配位址的指標重新分配空間,引數ptr為原有的空間指標,newsize為重新申請的位址長度。它與malloc的區別就是如果你給的指標是null,那麼你使用的就是malloc,如果你給出的指標是乙個已經分配了位址的指標(ptr),那麼你使用的就是realloc。

區別:(1)函式malloc不能初始化所分配的空間,而函式calloc能,也就是說,如果由malloc函式分配的空間原來沒有被分配過,則其中每一位都可能是0;反之,如果這一塊資料塊原來被分配過,那裡面可能遺留著各種各樣的資料。所以,當你在使用malloc開闢一塊新空間的時候,要重新初始化那一塊空間(一般呼叫memset函式來初始化空間)。否則在多次釋放、開闢之後,可能會出現使用錯誤。

(2)calloc函式會將所分配的記憶體空間中的每一位都初始化為0(這也是它和malloc的主要不同處之一)。也就是說,如果你是為字元類或者整形類的元素分配空間,那麼這些元素會保證被初始化為0;如果你是為指標類函式分配記憶體,那麼這些元素都會被初始化為空指標。

(3)malloc向系統申請size個位元組的空間,申請完之後返回的是這個空間的首位址,型別為void*,而void*表示未確定的型別,在c/c++中void*可以被強轉成任意型別的指標。

(4)realloc可以對給定的指標所指向的空間進行擴大或者縮小,無論是擴大還是縮小,原有記憶體中的內容將保持不變(如果對於縮小之後的空間,被縮小的那部分空間內的資料還是會丟失)。realloc並不保證調整後的記憶體空間和原來的記憶體空間保持同乙個位址。相反,realloc指標很可能指向乙個新的位址。

(5)realloc是從堆上分配空間的,但當你進行擴大的時候,realloc會試圖從堆上現存的資料後面的那些位元組中獲取附加的位元組,如果能滿足,就剛好。但如果後面的位元組數不夠,其就會使用堆上第乙個有足夠大小的自由塊,然後將現存的資料拷貝到新的位置,將老塊放回到堆上。在這個過程中,資料會被移動。也就是說,當你使用realloc的時候,資料可能被移動。

三、有關malloc的一些擴充套件(選自《高質量c/c++程式設計指南(林銳)》)

malloc 

malloc的原型:(void*)malloc(int size)(int也可以是unsigned,int只是其中的一種特例)

malloc函式的返回值是乙個void型別的指標,引數為int型別資料,即申請分配的記憶體大小,單位是byte。記憶體分配成功之後,malloc函式返回這塊記憶體的首位址。你需要乙個指標來接受這個位址。但是由於函式的返回值是void*型別,所以必須強制轉換成你所接收的型別。也就是說,這塊記憶體將來要儲存什麼型別的資料。比如:

char* p = (char*)malloc(100);

在堆上面分配了100個位元組記憶體,返回這塊記憶體的首位址,把位址強制轉換成char*型別後賦給char*型別 的指標變數p。同時告訴我們這塊記憶體將來用來儲存char*型別的資料。也就是說你只能通過指標變數p來操作這塊記憶體。這塊記憶體本身並沒有名字,對它的訪問是匿名訪問。

記憶體釋放

free函式做的事情:斬斷指標變數與這塊記憶體的關係。就像上面的例子一樣malloc函式開闢的這乙個資料塊空間是屬於p的,你只能通過p來訪問這一塊資料塊空間,而free函式做的事情就是斬斷malloc和p之間的聯絡。但是p指標本身存放的位址並沒有發生變化,只是它對指標所指向的那塊記憶體已經沒有所有權了,不能對記憶體塊進行操作。而那塊記憶體塊裡面的資料也沒有被改變,只是你沒有辦法去訪問或者修改那塊資料快中的內容了。

malloc和free是一一對應的,如果malloc兩次但是只free一次就會存在記憶體洩漏,如果malloc一次但是free了兩次,就會出錯(第一次使用free的時候,malloc所開闢的空間就已經被釋放,第二次使用free就無記憶體空間可以釋放了,這種對記憶體的誤操作就有可能會導致程式的崩潰)。

函式的記憶體釋放完後,一定要把p指標置為null。為什麼?

從上面可以看出,free掉之後p只是切斷了和記憶體空間的關係,但是p指標本身內部依舊存在乙個位址,如果不把它置成空,那這個指標就會變成乙個野指標(懸垂指標),遲早會出事。

例子:

1

char* p = (char*)malloc(100

);2 strcpy(p, "

hello");

3free(p);//

可以看到這邊已經釋放了p所指向的那一塊空間,但是p本身儲存的位址並沒有改變

4if(null != p)//

判斷不起作用,起不到防護作用

5

四、new/delete

前頭講了很多但好像還沒有講到c++的動態記憶體這方面。下面我們來進行一些討論。

我們知道c++是相容c的,那我們明明已經有了malloc和free來進行動態內容的管理,為什麼c++還要定義new和delete運算子來動態管理記憶體。

來看一下它們之間的區別和聯絡:

1.它們都是動態管理記憶體的入口。

2.malloc/free是c/c++標準庫的函式,new/delete是c++操作符。

3.malloc/free只是動態分配/釋放記憶體空間。而new/delete出來分配空間還會呼叫建構函式和析構函式進行初始化與清理。

4.malloc/free需要手動計算型別大小且會返回void*, new/delete可以自己計算型別的大小,返回對應型別的指標。

我們在c++中是允許進行過載的,那我們也可以過載一下new和delete,我在這就不做了(其實new和delete是不能過載的,即使你進行了過載,也只是過載了operator new和operator delete)。

有關operator new/operator delete    operator new/operator delete

總結:1.operator new/operator delete    operator new/operator delete的用法和malloc/free一樣。

2.它們只負責分配空間/釋放空間,不會呼叫物件建構函式和析構函式來初始化/清理物件。

3.實際operator new/operator delete  只是malloc和free的一層封裝。

五、new和delete在記憶體中所做的事

new做的事:

1.呼叫operator new分配空間

2.呼叫建構函式初始化空間

delete做的事:

1.呼叫析構函式清理物件

2.呼叫operator delete釋放空間

new[n]做的事:

1.呼叫operator new分配空間

2.呼叫n次建構函式分別初始化每個物件

delete做的事:

1.呼叫n次析構函式清理物件

2.呼叫operator delete釋放空間

用一張圖來解釋:

C 動態記憶體管理

我們都知道在c 中可以用new malloc動態分配記憶體空間,delete free釋放動態開闢的記憶體空間。1.那麼既然c 中有了可以動態開闢記憶體的函式為什麼又要有new delete呢?c 中的malloc free是繼承c語言中的malloc free,它的用法和在c語言中的用法一模一樣。...

C 動態記憶體管理

1 總結並剖析malloc free和new delete之間關係和差異。1 他們都是動態記憶體管理的入口 2 malloc要計算空間大小,返回值要強轉 new自動計算位元組大小,返回值是相應型別的指標 3 malloc只開闢空間 new開闢空間 呼叫建構函式初始化 delete呼叫析構函式清理 釋...

c 動態記憶體管理

c語言動態記憶體管理 c中關於動態記憶體的標準庫函式 malloc calloc realloc free 以下是關於這幾個函式的介紹 1 malloc 用於動態開闢記憶體 堆空間 返回型別為void 引數 size t size 是無符號整型表示要開闢的空間大小,單位是位元組,2 calloc 用...