深入理解C語言陣列與記憶體分配

2021-10-06 09:40:28 字數 1710 閱讀 7407

很多c語言教材都提到陣列長度的定義必須是常量,為什麼c語言陣列會有這種限制呢?這就要從程式變數的記憶體分配開始說起了。

我麼知道程式在執行時候資料、變數可能會存放的段有以下幾個:

堆區:malloc分配的記憶體就在這個區中

棧區:程式呼叫時函式內部的區域性變數在這個區中

.data區:這個區中的資料是程式開始執行前由作業系統的載入器將可執行檔案載入進入記憶體時建立的,用於存放程式中定義的已初始化全域性變數或者靜態變數

回到剛剛的問題,陣列會存放到哪幾個段中呢?

這個可能要和陣列的位置有關係了,我們分成幾種情況討論。

如果陣列定義成函式中的區域性變數,比如下面的**:

voidf1(

int n)

}int

main()

**中的陣列,屬於函式f1內的區域性變數,根據概述中的描述應該記憶體應該開闢在棧中。

棧中的變數有乙個很重要的特性就是當函式返回的後,變數占用的記憶體會被釋放。結合棧的filo的特性,對於乙個函式如果需要申請臨時變數僅僅需要將棧指標移動就很方便的為變數申請了空間。

回到這個問題如果在函式內部定義乙個陣列,而陣列的長度是不固定的,長度是由引數n決定的是否可行呢?

答案是可行的,僅僅需要程式在執行時將程式傳入的變數n*陣列每個元素的長度就可以得出陣列的長度。然後移動堆疊指標sp 陣列長度就為陣列分配出了記憶體。

事實上c89之後的編譯器也的確允許這樣定義。

這個特性相對於使用malloc函式還是有好處的,

不需要程式設計師考慮記憶體管理,不會造成記憶體洩漏。

效率相對於malloc的夥伴演算法會快

不會造成記憶體碎片

如果陣列定義成函式內的靜態變數,比如下面的**:

voidf1(

int n)

}int

main()

靜態變數的記憶體時在程式載入時分配在.data段的,由於此時程式尚未執行,不能確定函式引數n的值,無法確定申請記憶體的大小。因此這種情況編譯器不能通過。我們嘗試拿該**編譯會報錯

test.c:8:

13: error: storage size of 『array』 isn』t constant

static

int array[n]

;

如果陣列定義成全域性變數呢,比如下面的**:

int size =10;

int array[size]

;voidf1(

int n)

}int

main()

全域性變數記憶體空間的申請也是需要在程式載入初期由載入器初始化,這種情況下的陣列記憶體分配到.data段中,基於上段相似的理由,編譯器無法支援,會報如下錯誤:

test.c:5:

5: error: variably modified 『array』 at file scope

int array[size]

;^

c語言在定義陣列時是否允許使用變數指定陣列長度呢?

答案是分情況,

如果陣列定義在函式內部時,編譯器會力所能及的幫我們實現變數長度定義陣列。

其他的情況由於記憶體空間在程式載入時就需要知道陣列占用的空間大小,所以編譯器無計可施只能報錯。

深入理解c語言陣列

一 陣列名是什麼 陣列就是一段連續可用的記憶體。比如宣告乙個 int陣列 int array array代表什麼?有的資料說 陣列名是指向陣列首位址的常量指標。下面我們可以驗證一下。我都知道sizeof操作符可以返回乙個物件或者型別所佔的記憶體位元組數。如 int i 1 那麼sizeof i 的結...

深入理解Go語言 07 記憶體分配原理

在說明golang記憶體分配之前,先了解下linux系統記憶體相關的基礎知識,有助於理解golang記憶體分配原理。在早期記憶體管理中,如果程式太大,超過了空閒記憶體容量,就沒有辦法把全部程式裝入到記憶體,這時怎麼辦?在許多年前,人們採用了一種叫做覆蓋技術,這樣一種解決方案。這是一種什麼樣的解決方案...

深入理解C語言 深入理解記憶體四區

當陣列做函式引數的時候,會退化為乙個指標 此時在函式內是得不到陣列大小的 因此,陣列做函式引數的時候需要傳遞陣列大小,也就是多傳遞乙個引數 void func int arr,int num 若存在以上函式,c c 編譯器在編譯的時候,會將陣列優化為乙個指標,指向陣列的首位址,因此無法通過sizeo...