C之數據存儲方式(三十五)
A、程序中的棧
棧是現代計算機程序裏最為重要的概念之一,棧是用於維護函數調用上下文,同樣函數中的參數和局部變量存儲在棧上。棧保存了一個函數調用所需的維護信息,如下圖所示
那麽每次函數調用都對應著一個棧上的活動記錄:a> 調用函數的活動記錄位於棧的中部;b> 被調函數的活動記錄位於棧的頂部。
從 main() 開始運行,我們看到有兩個指針 ebp 和 esp。
那麽當 main() 調用 f() 時,ebp 就往前走四個字節,指向原來 esp 的位置。esp 也繼續向前走
當從 f() 調用總返回 main() 時,ebp 和 esp 都向回退四個字節。
那麽我們看到函數調用時,對應的棧空間在函數返回前是專用的。當函數調用後棧空間將被釋放,數據不再有效。下圖更形象的表示了
下來我們以代碼為例進行分析
#include <stdio.h> int* g() { int a[10] = {0}; return a; } void f() { int* pointer = g(); } int main() { f(); return 0; }
我們看到在函數 g() 中定義了一個數組,但是我們返回了它的地址,也就是返回了局部數組的地址。在 f() 中調用了 g(),這樣肯定會出問題,我們來看看編譯結果
我們看到編譯器已經給出了警告,那麽這麽操作肯定是不安全的。
B、程序中的堆
那麽什麽是堆呢?堆是程序中一塊預留的內存空間,可由程序自由使用,堆中被程序申請使用的內存在被主動釋放前將一直有效。那麽我們為什麽有了棧還需要堆呢?棧上的數據在函數返回後就會被釋放掉,無法傳遞到函數外部,如:局部數組。那麽堆則不一樣,如果我們不去主動釋放,它就一直有效,但是也就造成了一個問題,如果我們只申請不去釋放堆,到最後堆用完了程序便會崩潰。
那麽我們在程序中怎麽來申請堆呢?在 C 語言程序中通過庫函數的調用來獲得堆空間。對應的頭文件是 malloc.h;malloc 是以字節的方式動態申請堆空間;free 是將堆空間歸還給系統。系統對堆空間的管理方式有這麽幾種:空閑鏈表法、位圖法以及對象池法
下圖是空閑鏈表管理法的示意圖
如果我們需要申請 4 字節的話,根據這個表來看,我們便會申請到跟它最匹配的,便是 5 字節了。所以有時我們申請的空間會比我們所需的大一點。
C、程序中的靜態存儲區
靜態存儲區是隨著程序的運行而分配空間,它的生命周期直到程序運行結束。在程序的編譯器靜態存儲區的大小就已經確定,主要用於保存全局變量和靜態局部變量,它保存的信息最終會保存到可執行程序中。
下來我們以代碼為例來進行分析
#include <stdio.h> int g_v = 1; static int g_vs = 2; void f() { static int g_vl = 3; printf("&g_vl = %p\n", &g_vl); } int main() { printf("&g_v = %p\n", &g_v); printf("&g_vs = %p\n", &g_vs); f(); return 0; }
我們看到分別定義了三個變量,第3行是 int 型的全局變量,第5行是加 static 修飾的 int 型變量,第9行是加 static 修飾的函數內的局部變量。我們分別來打印下三個變量的地址,看看他們有什麽關系
那麽我們看到雖然他們三個類型不同,但是地址是連續的,也就證明他們三個是分布在同一個數據區的,便是靜態存儲區啦。通過本節對棧、堆以及靜態存儲區的學習,總結如下:1、棧區主要用於函數調用的使用;2、堆區主要是用於內存的動態申請和歸還;3、靜態存儲區用於保存全局變量和靜態變量。
歡迎大家一起來學習 C 語言,可以加我QQ:243343083。
C之數據存儲方式(三十五)