C語言 動態記憶體管理

2021-10-12 08:37:25 字數 3603 閱讀 5668

經典筆試題目

柔性陣列

首先,在了解乙個東西的時候,我們需要先知道,為什麼存在?每乙個事物的存在都是有它的意義的。我們以往定義乙個變數是這樣的:

int

main()

在棧上開闢空間有兩個特點:

空間開闢大小是固定的。(空間是有限的)

陣列在宣告的時候,必須指定陣列的長度,它所需要的內存在編譯時分配。例:我們定義乙個陣列的時候,必須要給他乙個具體的大小,即陣列的元素個數。

然而,我們的有些情況,陣列的大小根本無法確定,具體的大小是在程式跑起來之後,才可以知道,所以,動態開闢因此而生。

void

*malloc

(size_t size)

;

現在我們可以動態開闢空間了,那麼與之對應的就有乙個問題,這段空間該如何釋放呢?

那麼我們又有乙個問題了,之前我定義乙個變數都沒有管過它呀,我只需要定義和使用就可以了。甚至還很納悶,記憶體需要釋放嗎?

我們之前定義的變數,他們的空間都是在記憶體中的棧區的棧幀上定義的,棧是乙個高效的空間,他會自動為你開闢空間,當函式呼叫結束的時候,棧幀被釋放,變數的空間相應的就也被釋放了。

但是,現在我們是在堆區開闢的空間,它可以給你動態的開闢你想要的空間,但是它不會像棧一樣,去自動的幫你去釋放空間,所以c語言,提供了專用於釋放動態開闢的空間的函式,free因此而生。

free函式原型如下:

void

free

(void

* ptr)

;

malloc在堆上申請空間,程式設計師申請,程式設計師釋放。如果不釋放,會有記憶體洩漏,但是程式退出,記憶體洩漏隨機消失(作業系統收回)。

mallocfree都宣告在stdlib.h標頭檔案中。

函式原型如下:

void

*calloc

(size_t num, size_t size)

;

callocmalloc的區別僅僅只是,乙個會初始化所有元素,乙個僅僅是開闢空間。

在有些時候,我們可能會覺得前面動態開闢的空間(malloc或者calloc)有點小了或者是大了。我們為了合理的使用記憶體,我們就需要對記憶體進行靈活的調整,realloc函式因此而生。

函式原型如下:

void

*realloc

(void

* ptr,size_t size)

;

我們已經有了起始位址,為何還有給我們返回乙個新的起始位址呢?

在原來的空間後面有足夠大的空間,來容納現在realloc需求的空間,那麼就返回原來的起始位址,即起始位址不變。

在原來的空間後面沒有足夠大的空間,來容納現在realloc需求的空間,那麼函式會在堆區上另外找一塊足夠大的空間,把原空間的內容全部複製乙份過去,並且把原空間free,然後返回該新區域的起始位址。(具體指向順序可能並非如此)

void

getmemory

(char

* p)

void

test()

分析:test函式中呼叫getmemory函式的時候,傳入str,傳入的實際上是str的內容,在getmemory內部會形成乙個變數pstr的乙份拷貝(p在棧上開闢空間),即p->null,然後在getmemory函式內部動態開闢一塊空間,由p指向該堆空間,然後getmemory函式執行結束,相應的棧幀銷毀,p變數被釋放。現在(getmemory函式呼叫結束),str依舊指向nullp已經不存在。

存在問題:

由於原來只有p指向堆空間,現在p被釋放,堆空間未被釋放,且無法被找到,造成記憶體洩漏。

strcpy函式,傳入引數strnull,寫入位置錯誤。

char

*getmemory()

void

test()

分析:呼叫getmemory函式,函式會在棧區形成棧幀,並且定義乙個字元陣列,為陣列p開闢空間,恰好容納"hello world!",最後返回陣列p的位址,函式執行結束,棧幀銷毀,p陣列被釋放。

存在問題:

test函式呼叫getmemorystr被賦值為p的位址,但是,p陣列的所有內容,已經被釋放,緊接著會呼叫printf函式,在棧上形成棧幀,覆蓋剛剛的那片區域,所以該程式執行後,會在螢幕上輸出亂碼。

或許你從來沒有聽過柔性陣列這個概念,但是它確確實實是存在的。接下來,簡單講解什麼是柔性陣列。

typedef

struct st_typetype_a;

注意:有些編譯器寫成上面這種格式,可能會無法編譯。可以將柔性陣列成員a[0]改為a

特點:

為了在結構體內部動態的定義乙個陣列的大小,還有一種方式,就是在結構體內部定義想要的陣列的指標,然後再外面呼叫的時候,對其進行malloc()開闢並且將指標賦值。

這樣做相對於柔性陣列來說,有以下幾個缺點:

①記憶體如果開闢失敗,由於結構體本身需要開闢空間,內部陣列也需要開闢空間,2次的開闢空間,如果第二次開闢失敗,就還需要free掉第一次開闢的結構體的空間,比較麻煩。而且,如果全部成功,那麼在釋放的時候,為了避免記憶體洩漏,需要先釋放陣列的空間,再釋放結構體的空間,同樣比較麻煩。而柔性陣列就只需開闢一次成功,和釋放一次,實現同樣的功能,柔性陣列更加的方便。

②這種方式開闢出來的空間,不一定是連續的,但是柔性陣列的空間是連續的。連續的記憶體有益於提高訪問速度,也有益於減少記憶體碎片。

作者部落格:

C語言動態記憶體管理

1 概述 動態儲存管理的基本問題是 系統如何按請求分配記憶體,如何 記憶體再利用。提出請求的使用者可能是系統的乙個作業,也可能是程式中的乙個變數。空閒塊 未曾分配的位址連續的記憶體區稱為 空閒塊 占用塊 已分配給使用者使用的位址連續的記憶體區稱為 占用塊 系統剛剛啟動時,整個記憶體可看做乙個大的 空...

C語言動態記憶體管理

c系統的函式庫中提供了了程式動態申請和釋放記憶體儲存塊的庫函式,下面將分別介紹。1 malloc 函式 a 該函式的原型 void malloc size t size b 該函式只有乙個引數,且形參size是無符號整型,該引數代表申請空間的位元組數。c 返回值 如果記憶體池中的可用記憶體滿足需求,...

C語言動態記憶體管理

在說明c語言記憶體管理之前,要知道什麼是記憶體,記憶體我個人認為可以理解為帶有標籤的盒子,所謂的帶標籤的盒子就像我們住的寢室一樣有門牌號,盒子內只能儲存固定型別的資料或變數,就如男生寢室只能住男生一樣。那麼c語言中有多少種盒子呢?有靜態儲存區 動態儲存區 內部暫存器區域。我們通常定義的變數如果沒有特...